diff --git a/.buildkite/ftr_configs.yml b/.buildkite/ftr_configs.yml index 1e2bc2a852ac0..1d1ee79deee4a 100644 --- a/.buildkite/ftr_configs.yml +++ b/.buildkite/ftr_configs.yml @@ -555,8 +555,6 @@ enabled: - x-pack/test/security_solution_api_integration/test_suites/detections_response/telemetry/trial_license_complete_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/user_roles/trial_license_complete_tier/configs/ess.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/user_roles/trial_license_complete_tier/configs/serverless.config.ts - - x-pack/test/security_solution_api_integration/test_suites/genai/invoke_ai/trial_license_complete_tier/configs/ess.config.ts - - x-pack/test/security_solution_api_integration/test_suites/genai/invoke_ai/trial_license_complete_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/genai/nlp_cleanup_task/trial_license_complete_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/genai/nlp_cleanup_task/basic_license_essentials_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/entity_analytics/risk_engine/trial_license_complete_tier/configs/ess.config.ts diff --git a/.buildkite/pipelines/security_solution_quality_gate/mki_periodic/mki_periodic_gen_ai.yml b/.buildkite/pipelines/security_solution_quality_gate/mki_periodic/mki_periodic_gen_ai.yml index 3fe69ca56c38b..c9c80c823b227 100644 --- a/.buildkite/pipelines/security_solution_quality_gate/mki_periodic/mki_periodic_gen_ai.yml +++ b/.buildkite/pipelines/security_solution_quality_gate/mki_periodic/mki_periodic_gen_ai.yml @@ -21,20 +21,6 @@ steps: - group: "API MKI - GenAI" key: api_test_ai_assistant steps: - - label: Running genai:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh genai:qa:serverless - key: genai:qa:serverless - agents: - image: family/kibana-ubuntu-2004 - imageProject: elastic-images-prod - provider: gcp - machineType: n2-standard-4 - preemptible: true - timeout_in_minutes: 120 - retry: - automatic: - - exit_status: "1" - limit: 2 - label: Running nlp_cleanup_task:complete:qa:serverless command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh nlp_cleanup_task:complete:qa:serverless diff --git a/.buildkite/pipelines/security_solution_quality_gate/mki_quality_gate/mki_quality_gate_gen_ai.yml b/.buildkite/pipelines/security_solution_quality_gate/mki_quality_gate/mki_quality_gate_gen_ai.yml index 9ea5755438ef7..677a5c62f4cc0 100644 --- a/.buildkite/pipelines/security_solution_quality_gate/mki_quality_gate/mki_quality_gate_gen_ai.yml +++ b/.buildkite/pipelines/security_solution_quality_gate/mki_quality_gate/mki_quality_gate_gen_ai.yml @@ -21,21 +21,6 @@ steps: - group: "API MKI - GenAI" key: api_test_ai_assistant steps: - - label: Running genai:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh genai:qa:serverless:release - key: genai:qa:serverless:release - agents: - image: family/kibana-ubuntu-2004 - imageProject: elastic-images-prod - provider: gcp - machineType: n2-standard-4 - preemptible: true - timeout_in_minutes: 120 - retry: - automatic: - - exit_status: "1" - limit: 2 - - label: Running nlp_cleanup_task:complete:qa:serverless:release command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh nlp_cleanup_task:complete:qa:serverless:release key: nlp_cleanup_task:complete:qa:serverless:release diff --git a/.buildkite/scripts/steps/checks.sh b/.buildkite/scripts/steps/checks.sh index 2844d8eee212f..dd7c0c0e6d69c 100755 --- a/.buildkite/scripts/steps/checks.sh +++ b/.buildkite/scripts/steps/checks.sh @@ -13,4 +13,5 @@ fi .buildkite/scripts/steps/capture_oas_snapshot.sh .buildkite/scripts/steps/code_generation/elastic_assistant_codegen.sh .buildkite/scripts/steps/code_generation/security_solution_codegen.sh +.buildkite/scripts/steps/openapi_bundling/security_solution_openapi_bundling.sh .buildkite/scripts/steps/code_generation/osquery_codegen.sh diff --git a/.buildkite/scripts/steps/openapi_bundling/security_solution_openapi_bundling.sh b/.buildkite/scripts/steps/openapi_bundling/security_solution_openapi_bundling.sh old mode 100644 new mode 100755 index be17669d980b6..51d269257e887 --- a/.buildkite/scripts/steps/openapi_bundling/security_solution_openapi_bundling.sh +++ b/.buildkite/scripts/steps/openapi_bundling/security_solution_openapi_bundling.sh @@ -8,3 +8,9 @@ echo --- Security Solution OpenAPI Bundling (cd x-pack/plugins/security_solution && yarn openapi:bundle) check_for_changed_files "yarn openapi:bundle" true + +(cd packages/kbn-securitysolution-lists-common && yarn openapi:bundle) +check_for_changed_files "yarn openapi:bundle" true + +(cd packages/kbn-securitysolution-exceptions-common && yarn openapi:bundle) +check_for_changed_files "yarn openapi:bundle" true \ No newline at end of file diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 02a7089559662..bdfb27e11e135 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -50,6 +50,7 @@ test/plugin_functional/plugins/app_link_test @elastic/kibana-core x-pack/test/usage_collection/plugins/application_usage_test @elastic/kibana-core x-pack/plugins/observability_solution/assets_data_access @elastic/obs-knowledge-team x-pack/test/security_api_integration/plugins/audit_log @elastic/kibana-security +packages/kbn-avc-banner @elastic/security-defend-workflows packages/kbn-axe-config @elastic/kibana-qa packages/kbn-babel-preset @elastic/kibana-operations packages/kbn-babel-register @elastic/kibana-operations @@ -737,6 +738,7 @@ x-pack/plugins/security @elastic/kibana-security x-pack/packages/security/plugin_types_common @elastic/kibana-security x-pack/packages/security/plugin_types_public @elastic/kibana-security x-pack/packages/security/plugin_types_server @elastic/kibana-security +x-pack/packages/security-solution/distribution_bar @elastic/kibana-cloud-security-posture x-pack/plugins/security_solution_ess @elastic/security-solution x-pack/packages/security-solution/features @elastic/security-threat-hunting-explore x-pack/test/cases_api_integration/common/plugins/security_solution @elastic/response-ops @@ -1724,6 +1726,10 @@ packages/react @elastic/appex-sharedux /x-pack/plugins/ml/common/openapi @elastic/platform-docs /packages/core/saved-objects/docs/openapi @elastic/platform-docs /plugins/data_views/docs/openapi @elastic/platform-docs +oas_docs/.spectral.yaml @elastic/platform-docs +oas_docs/kibana.info.serverless.yaml @elastic/platform-docs +oas_docs/kibana.serverless.yaml @elastic/platform-docs +oas_docs/makefile @elastic/platform-docs # Plugin manifests /src/plugins/**/kibana.jsonc @elastic/kibana-core diff --git a/.github/workflows/bump.yml b/.github/workflows/bump.yml deleted file mode 100644 index 4e8bd45fd8690..0000000000000 --- a/.github/workflows/bump.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: Check & deploy API documentation - -on: - push: - branches: - - main - paths: - - 'oas_docs/kibana.serverless.yaml' - - pull_request: - branches: - - main - paths: - - 'oas_docs/kibana.serverless.yaml' - -permissions: - contents: read - pull-requests: write - -jobs: - deploy-doc: - if: ${{ github.event_name == 'push' }} - name: Deploy API documentation on Bump.sh - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Deploy API documentation - uses: bump-sh/github-action@v1 - with: - doc: serverless - token: ${{secrets.BUMP_TOKEN}} - file: oas_docs/kibana.serverless.yaml - - api-diff: - if: ${{ github.event_name == 'pull_request' }} - name: Check API diff on Bump.sh - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Create Preview - uses: bump-sh/github-action@v1 - with: - doc: serverless - token: ${{secrets.BUMP_TOKEN}} - file: oas_docs/kibana.serverless.yaml - command: preview - env: - GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} - - name: Comment pull request with API diff - uses: bump-sh/github-action@v1 - with: - doc: serverless - token: ${{secrets.BUMP_TOKEN}} - file: oas_docs/kibana.serverless.yaml - command: diff - fail_on_breaking: true - env: - GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} diff --git a/.i18nrc.json b/.i18nrc.json index bab7cdc68d81d..59e33320eeea1 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -7,6 +7,7 @@ "alertingTypes": "packages/kbn-alerting-types", "apmOss": "src/plugins/apm_oss", "autocomplete": "packages/kbn-securitysolution-autocomplete/src", + "avcBanner": "packages/kbn-avc-banner/src", "bfetch": "src/plugins/bfetch", "bfetchError": "packages/kbn-bfetch-error", "cases": ["packages/kbn-cases-components"], diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index 453d0ed448e19..00c16261f2517 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-07-17 +date: 2024-07-19 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 9f7bcec3d665d..bfde1502c4fc2 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-07-17 +date: 2024-07-19 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 3df614698253b..da1376b6baec0 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-07-17 +date: 2024-07-19 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 1fa59ce91cad2..f5511b3178e6d 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-07-17 +date: 2024-07-19 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 a5ee66dbcec93..4bc0a7f8b7dcb 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-07-17 +date: 2024-07-19 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 ef7e758ec5d13..f34bf96fdde6b 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-07-17 +date: 2024-07-19 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 7817dd3a50e78..87c0554142f26 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apmDataAccess'] --- import apmDataAccessObj from './apm_data_access.devdocs.json'; diff --git a/api_docs/assets_data_access.mdx b/api_docs/assets_data_access.mdx index 06e1600d96d29..2fe70b90d77c1 100644 --- a/api_docs/assets_data_access.mdx +++ b/api_docs/assets_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/assetsDataAccess title: "assetsDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the assetsDataAccess plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'assetsDataAccess'] --- import assetsDataAccessObj from './assets_data_access.devdocs.json'; diff --git a/api_docs/banners.mdx b/api_docs/banners.mdx index e249e814db866..2fa385f88c281 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-07-17 +date: 2024-07-19 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 41b84b947025d..2bd453954e600 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-07-17 +date: 2024-07-19 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 bf471d5b2dfe7..12a1ff5a844d8 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-07-17 +date: 2024-07-19 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 5404406735869..59a5d2e137b34 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-07-17 +date: 2024-07-19 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 feef4d7c01f29..ca7163b13cdf7 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-07-17 +date: 2024-07-19 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 e359e2766f321..b0f2181dd160a 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-07-17 +date: 2024-07-19 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 d032ca0cfba0a..d297ee26055d6 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-07-17 +date: 2024-07-19 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 3985fac3f26f9..16ed9d2b70716 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudDefend'] --- import cloudDefendObj from './cloud_defend.devdocs.json'; diff --git a/api_docs/cloud_experiments.devdocs.json b/api_docs/cloud_experiments.devdocs.json index 76d3f7adecb5c..55907b5ad929d 100644 --- a/api_docs/cloud_experiments.devdocs.json +++ b/api_docs/cloud_experiments.devdocs.json @@ -133,26 +133,6 @@ "plugin": "navigation", "path": "src/plugins/navigation/public/types.ts" }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/components/utils.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/components/utils.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/components/utils.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/plugin_contract.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/plugin_contract.ts" - }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/types.ts" @@ -161,14 +141,6 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/types.ts" }, - { - "plugin": "securitySolutionEss", - "path": "x-pack/plugins/security_solution_ess/public/types.ts" - }, - { - "plugin": "securitySolutionEss", - "path": "x-pack/plugins/security_solution_ess/public/types.ts" - }, { "plugin": "cloudChat", "path": "x-pack/plugins/cloud_integrations/cloud_chat/server/plugin.ts" @@ -185,18 +157,6 @@ "plugin": "observabilityOnboarding", "path": "x-pack/plugins/observability_solution/observability_onboarding/public/plugin.ts" }, - { - "plugin": "securitySolutionEss", - "path": "x-pack/plugins/security_solution_ess/public/common/hooks/use_variation.ts" - }, - { - "plugin": "securitySolutionEss", - "path": "x-pack/plugins/security_solution_ess/public/common/hooks/use_variation.ts" - }, - { - "plugin": "securitySolutionEss", - "path": "x-pack/plugins/security_solution_ess/public/common/hooks/use_variation.ts" - }, { "plugin": "navigation", "path": "src/plugins/navigation/server/types.ts" @@ -219,7 +179,7 @@ "\nFetch the configuration assigned to variation `configKey`. If nothing is found, fallback to `defaultValue`." ], "signature": [ - "(featureFlagName: \"security-solutions.add-integrations-url\" | \"security-solutions.guided-onboarding-content\" | \"cloud-chat.enabled\" | \"cloud-chat.chat-variant\" | \"observability_onboarding.experimental_onboarding_flow_enabled\" | \"solutionNavEnabled\", defaultValue: Data) => Promise" + "(featureFlagName: \"security-solutions.add-integrations-url\" | \"cloud-chat.enabled\" | \"cloud-chat.chat-variant\" | \"observability_onboarding.experimental_onboarding_flow_enabled\" | \"solutionNavEnabled\", defaultValue: Data) => Promise" ], "path": "x-pack/plugins/cloud_integrations/cloud_experiments/common/types.ts", "deprecated": true, @@ -233,14 +193,6 @@ "plugin": "navigation", "path": "src/plugins/navigation/public/plugin.tsx" }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/components/utils.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/plugin.ts" - }, { "plugin": "cloudChat", "path": "x-pack/plugins/cloud_integrations/cloud_chat/server/plugin.ts" @@ -249,18 +201,6 @@ "plugin": "cloudChat", "path": "x-pack/plugins/cloud_integrations/cloud_chat/server/plugin.ts" }, - { - "plugin": "securitySolutionEss", - "path": "x-pack/plugins/security_solution_ess/public/common/hooks/use_variation.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/components/utils.test.ts" - }, - { - "plugin": "securitySolutionEss", - "path": "x-pack/plugins/security_solution_ess/public/common/hooks/use_variation.test.ts" - }, { "plugin": "navigation", "path": "src/plugins/navigation/public/plugin.test.ts" @@ -285,7 +225,7 @@ "The name of the key to find the config variation. {@link CloudExperimentsFeatureFlagNames }." ], "signature": [ - "\"security-solutions.add-integrations-url\" | \"security-solutions.guided-onboarding-content\" | \"cloud-chat.enabled\" | \"cloud-chat.chat-variant\" | \"observability_onboarding.experimental_onboarding_flow_enabled\" | \"solutionNavEnabled\"" + "\"security-solutions.add-integrations-url\" | \"cloud-chat.enabled\" | \"cloud-chat.chat-variant\" | \"observability_onboarding.experimental_onboarding_flow_enabled\" | \"solutionNavEnabled\"" ], "path": "x-pack/plugins/cloud_integrations/cloud_experiments/common/types.ts", "deprecated": false, @@ -382,7 +322,7 @@ "\nThe names of the feature flags declared in Kibana.\nValid keys are defined in {@link FEATURE_FLAG_NAMES}. When using a new feature flag, add the name to the list.\n" ], "signature": [ - "\"security-solutions.add-integrations-url\" | \"security-solutions.guided-onboarding-content\" | \"cloud-chat.enabled\" | \"cloud-chat.chat-variant\" | \"observability_onboarding.experimental_onboarding_flow_enabled\" | \"solutionNavEnabled\"" + "\"security-solutions.add-integrations-url\" | \"cloud-chat.enabled\" | \"cloud-chat.chat-variant\" | \"observability_onboarding.experimental_onboarding_flow_enabled\" | \"solutionNavEnabled\"" ], "path": "x-pack/plugins/cloud_integrations/cloud_experiments/common/types.ts", "deprecated": false, diff --git a/api_docs/cloud_experiments.mdx b/api_docs/cloud_experiments.mdx index b496f50b8c13c..be5f016253908 100644 --- a/api_docs/cloud_experiments.mdx +++ b/api_docs/cloud_experiments.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudExperiments title: "cloudExperiments" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudExperiments plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudExperiments'] --- import cloudExperimentsObj from './cloud_experiments.devdocs.json'; diff --git a/api_docs/cloud_security_posture.mdx b/api_docs/cloud_security_posture.mdx index e74bf8e3a61df..b7151fd85e259 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-07-17 +date: 2024-07-19 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 17f0c922a1ebb..97a4ddc18543d 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-07-17 +date: 2024-07-19 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 a1376f7078e49..054d02991adda 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'contentManagement'] --- import contentManagementObj from './content_management.devdocs.json'; diff --git a/api_docs/controls.mdx b/api_docs/controls.mdx index 41622450e1284..9aaea6b472a46 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'controls'] --- import controlsObj from './controls.devdocs.json'; diff --git a/api_docs/custom_integrations.mdx b/api_docs/custom_integrations.mdx index f65ed755c0999..f6ed73607fa8a 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'customIntegrations'] --- import customIntegrationsObj from './custom_integrations.devdocs.json'; diff --git a/api_docs/dashboard.mdx b/api_docs/dashboard.mdx index 16e558f673c5d..6b51925e126a6 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboard'] --- import dashboardObj from './dashboard.devdocs.json'; diff --git a/api_docs/dashboard_enhanced.mdx b/api_docs/dashboard_enhanced.mdx index bde0ac00f7916..71a37590289f0 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-07-17 +date: 2024-07-19 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 04f3b8d33eee6..19e39419c00cd 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-07-17 +date: 2024-07-19 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 3e004c9ee3be1..c41276b49c484 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-07-17 +date: 2024-07-19 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 fde26e2172b84..574fe3340cb0c 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-07-17 +date: 2024-07-19 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 7f73ada1e2d7d..e0b4adb355918 100644 --- a/api_docs/data_search.devdocs.json +++ b/api_docs/data_search.devdocs.json @@ -3611,7 +3611,15 @@ "label": "uiSettingsClient", "description": [], "signature": [ - "{ get: (key: string) => Promise; }" + "{ get: (key: string, context?: ", + { + "pluginId": "@kbn/core-ui-settings-common", + "scope": "common", + "docId": "kibKbnCoreUiSettingsCommonPluginApi", + "section": "def-common.GetUiSettingsContext", + "text": "GetUiSettingsContext" + }, + " | undefined) => Promise; }" ], "path": "src/plugins/data/server/search/types.ts", "deprecated": false, diff --git a/api_docs/data_search.mdx b/api_docs/data_search.mdx index 26d81f6d2b1db..447bb62617159 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.search'] --- import dataSearchObj from './data_search.devdocs.json'; diff --git a/api_docs/data_view_editor.mdx b/api_docs/data_view_editor.mdx index 155de8e193f87..695d571deef7f 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-07-17 +date: 2024-07-19 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 0664286f7520d..56d54c439d8fc 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-07-17 +date: 2024-07-19 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 0abc78759ee41..238ff60682f35 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-07-17 +date: 2024-07-19 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 e03d857c17cc0..fb82fa8985d35 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-07-17 +date: 2024-07-19 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 3158501e3f897..8a0a62c2c8a28 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataVisualizer'] --- import dataVisualizerObj from './data_visualizer.devdocs.json'; diff --git a/api_docs/dataset_quality.mdx b/api_docs/dataset_quality.mdx index 4858138cb6f11..e8e8fe63a63cf 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-07-17 +date: 2024-07-19 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 9151282b51a91..f3667d1680418 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -32,8 +32,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | @kbn/core, visualizations, triggersActionsUi | - | | | ruleRegistry, securitySolution, synthetics, slo | - | | | security, actions, alerting, ruleRegistry, files, cases, fleet, securitySolution | - | -| | spaces, navigation, securitySolution, securitySolutionEss, cloudChat, observabilityOnboarding | - | -| | spaces, navigation, securitySolution, cloudChat, securitySolutionEss | - | +| | spaces, navigation, securitySolution, cloudChat, observabilityOnboarding | - | | | alerting, discover, securitySolution | - | | | @kbn/core-saved-objects-api-browser, @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-browser-mocks, @kbn/core-saved-objects-api-server-internal, @kbn/core-saved-objects-import-export-server-internal, @kbn/core-saved-objects-server-internal, fleet, graph, lists, osquery, securitySolution, alerting | - | | | @kbn/core-saved-objects-api-browser, @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-browser-mocks, @kbn/core-saved-objects-api-server-internal, @kbn/core-saved-objects-import-export-server-internal, @kbn/core-saved-objects-server-internal, fleet, graph, lists, osquery, securitySolution, alerting | - | @@ -68,6 +67,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | @kbn/monaco, securitySolution | - | | | fleet, cloudSecurityPosture, exploratoryView, osquery, synthetics | - | | | alerting, observabilityAIAssistant, fleet, cloudSecurityPosture, enterpriseSearch, serverlessSearch, transform, upgradeAssistant, apm, entityManager, observabilityOnboarding, synthetics, security | - | +| | spaces, navigation, cloudChat | - | | | @kbn/core-saved-objects-browser-internal, @kbn/core, spaces, savedSearch, visualizations, lens, cases, maps, canvas, graph | - | | | spaces, savedObjectsManagement | - | | | @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 | - | @@ -173,10 +173,10 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | spaces, security, actions, alerting, aiops, remoteClusters, ml, graph, indexLifecycleManagement, mapsEms, osquery, securitySolution, painlessLab, rollup, searchprofiler, snapshotRestore, transform, upgradeAssistant | 8.8.0 | | | fleet, apm, security, securitySolution | 8.8.0 | | | fleet, apm, security, securitySolution | 8.8.0 | -| | spaces, security, alerting, cases | 8.8.0 | +| | spaces, security, alerting, cases | 8.8.0 | | | embeddable, presentationUtil, lens, dashboard, discover, graph, links | 8.8.0 | | | @kbn/core-application-browser-internal, @kbn/core-application-browser-mocks, management, fleet, security, kibanaOverview, @kbn/core | 8.8.0 | -| | security | 8.8.0 | +| | security | 8.8.0 | | | apm | 8.8.0 | | | mapsEms | 8.8.0 | | | savedObjectsTaggingOss | 8.8.0 | diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index 7f918fc164ca1..752777f5e6102 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -476,7 +476,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [retrieve_migrated_legacy_actions.mock.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.mock.ts#:~:text=migrationVersion), [retrieve_migrated_legacy_actions.mock.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.mock.ts#:~:text=migrationVersion), [retrieve_migrated_legacy_actions.mock.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.mock.ts#:~:text=migrationVersion), [retrieve_migrated_legacy_actions.mock.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.mock.ts#:~:text=migrationVersion), [retrieve_migrated_legacy_actions.mock.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.mock.ts#:~:text=migrationVersion), [retrieve_migrated_legacy_actions.mock.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.mock.ts#:~:text=migrationVersion), [retrieve_migrated_legacy_actions.mock.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.mock.ts#:~:text=migrationVersion), [retrieve_migrated_legacy_actions.mock.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.mock.ts#:~:text=migrationVersion), [retrieve_migrated_legacy_actions.mock.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.mock.ts#:~:text=migrationVersion), [retrieve_migrated_legacy_actions.mock.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.mock.ts#:~:text=migrationVersion)+ 10 more | - | | | [wrap_search_source_client.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/lib/wrap_search_source_client.ts#:~:text=create) | - | | | [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/lib/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/lib/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/lib/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/lib/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/lib/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/lib/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/lib/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/lib/wrap_search_source_client.test.ts#:~:text=fetch) | - | -| | [plugin.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/plugin.test.ts#:~:text=getKibanaFeatures) | 8.8.0 | +| | [plugin.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/plugin.test.ts#:~:text=getKibanaFeatures) | 8.8.0 | | | [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/plugin.ts#:~:text=license%24), [license_state.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/lib/license_state.test.ts#:~:text=license%24), [license_state.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/lib/license_state.test.ts#:~:text=license%24) | 8.8.0 | | | [rules_client_factory.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/rules_client_factory.ts#:~:text=authc), [task.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/invalidate_pending_api_keys/task.ts#:~:text=authc), [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/plugin.ts#:~:text=authc), [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/plugin.ts#:~:text=authc), [rules_client_factory.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/rules_client_factory.ts#:~:text=authc), [task.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/invalidate_pending_api_keys/task.ts#:~:text=authc), [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/plugin.ts#:~:text=authc), [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/plugin.ts#:~:text=authc) | - | | | [task.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/usage/task.ts#:~:text=index) | - | @@ -539,7 +539,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| -| | [factory.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cases/server/client/factory.test.ts#:~:text=getKibanaFeatures) | 8.8.0 | +| | [factory.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cases/server/client/factory.test.ts#:~:text=getKibanaFeatures) | 8.8.0 | | | [email_notification_service.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cases/server/services/notifications/email_notification_service.ts#:~:text=userProfiles), [factory.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cases/server/client/factory.ts#:~:text=userProfiles), [utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cases/server/client/cases/utils.ts#:~:text=userProfiles), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cases/server/services/user_profiles/index.ts#:~:text=userProfiles), [email_notification_service.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cases/server/services/notifications/email_notification_service.ts#:~:text=userProfiles), [factory.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cases/server/client/factory.ts#:~:text=userProfiles), [utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cases/server/client/cases/utils.ts#:~:text=userProfiles), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cases/server/services/user_profiles/index.ts#:~:text=userProfiles) | - | | | [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cases/common/ui/types.ts#:~:text=ResolvedSimpleSavedObject), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cases/common/ui/types.ts#:~:text=ResolvedSimpleSavedObject), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cases/common/ui/types.ts#:~:text=ResolvedSimpleSavedObject), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cases/common/ui/types.ts#:~:text=ResolvedSimpleSavedObject) | - | | | [cases.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cases/server/saved_object_types/cases/cases.ts#:~:text=migrations), [configure.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cases/server/saved_object_types/configure.ts#:~:text=migrations), [comments.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cases/server/saved_object_types/comments.ts#:~:text=migrations), [user_actions.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cases/server/saved_object_types/user_actions.ts#:~:text=migrations), [connector_mappings.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cases/server/saved_object_types/connector_mappings.ts#:~:text=migrations) | - | @@ -1311,8 +1311,8 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ This is relied on by the reporting feature, and should be removed once reporting migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/issues/19914 | -| | [app_authorization.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/app_authorization.ts#:~:text=getKibanaFeatures), [privileges.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.ts#:~:text=getKibanaFeatures), [authorization_service.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/authorization_service.tsx#:~:text=getKibanaFeatures), [app_authorization.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/app_authorization.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts#:~:text=getKibanaFeatures)+ 24 more | 8.8.0 | -| | [authorization_service.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/authorization_service.tsx#:~:text=getElasticsearchFeatures) | 8.8.0 | +| | [app_authorization.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/app_authorization.ts#:~:text=getKibanaFeatures), [privileges.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.ts#:~:text=getKibanaFeatures), [authorization_service.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/authorization_service.tsx#:~:text=getKibanaFeatures), [app_authorization.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/app_authorization.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts#:~:text=getKibanaFeatures)+ 24 more | 8.8.0 | +| | [authorization_service.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/authorization_service.tsx#:~:text=getElasticsearchFeatures) | 8.8.0 | | | [license_service.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/common/licensing/license_service.test.ts#:~:text=mode), [license_service.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/common/licensing/license_service.test.ts#:~:text=mode), [license_service.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/common/licensing/license_service.test.ts#:~:text=mode) | 8.8.0 | | | [plugin.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/plugin.tsx#:~:text=license%24) | 8.8.0 | | | [license_service.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/common/licensing/license_service.test.ts#:~:text=mode), [license_service.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/common/licensing/license_service.test.ts#:~:text=mode), [license_service.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/common/licensing/license_service.test.ts#:~:text=mode) | 8.8.0 | @@ -1333,8 +1333,7 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| | | [route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/route.ts#:~:text=alertFactory) | - | -| | [utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/utils.ts#:~:text=CloudExperimentsPluginStart), [utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/utils.ts#:~:text=CloudExperimentsPluginStart), [utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/utils.ts#:~:text=CloudExperimentsPluginStart), [plugin_contract.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/plugin_contract.ts#:~:text=CloudExperimentsPluginStart), [plugin_contract.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/plugin_contract.ts#:~:text=CloudExperimentsPluginStart), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/types.ts#:~:text=CloudExperimentsPluginStart), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/types.ts#:~:text=CloudExperimentsPluginStart) | - | -| | [utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/utils.ts#:~:text=getVariation), [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/plugin.ts#:~:text=getVariation), [utils.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/utils.test.ts#:~:text=getVariation) | - | +| | [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/types.ts#:~:text=CloudExperimentsPluginStart), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/types.ts#:~:text=CloudExperimentsPluginStart) | - | | | [wrap_search_source_client.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.ts#:~:text=create) | - | | | [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts#:~:text=fetch) | - | | | [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=migrationVersion), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=migrationVersion), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=migrationVersion), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=migrationVersion), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=migrationVersion), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=migrationVersion), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=migrationVersion), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=migrationVersion), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=migrationVersion), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=migrationVersion)+ 12 more | - | @@ -1382,15 +1381,6 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ -## securitySolutionEss - -| Deprecated API | Reference location(s) | Remove By | -| ---------------|-----------|-----------| -| | [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution_ess/public/types.ts#:~:text=CloudExperimentsPluginStart), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution_ess/public/types.ts#:~:text=CloudExperimentsPluginStart), [use_variation.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution_ess/public/common/hooks/use_variation.ts#:~:text=CloudExperimentsPluginStart), [use_variation.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution_ess/public/common/hooks/use_variation.ts#:~:text=CloudExperimentsPluginStart), [use_variation.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution_ess/public/common/hooks/use_variation.ts#:~:text=CloudExperimentsPluginStart) | - | -| | [use_variation.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution_ess/public/common/hooks/use_variation.ts#:~:text=getVariation), [use_variation.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution_ess/public/common/hooks/use_variation.test.ts#:~:text=getVariation) | - | - - - ## serverlessSearch | Deprecated API | Reference location(s) | Remove By | @@ -1431,7 +1421,7 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | ---------------|-----------|-----------| | | [is_solution_nav_enabled.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/public/experiments/is_solution_nav_enabled.ts#:~:text=CloudExperimentsPluginStart), [is_solution_nav_enabled.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/public/experiments/is_solution_nav_enabled.ts#:~:text=CloudExperimentsPluginStart), [plugin.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/public/plugin.tsx#:~:text=CloudExperimentsPluginStart), [plugin.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/public/plugin.tsx#:~:text=CloudExperimentsPluginStart) | - | | | [is_solution_nav_enabled.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/public/experiments/is_solution_nav_enabled.ts#:~:text=getVariation) | - | -| | [on_post_auth_interceptor.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts#:~:text=getKibanaFeatures), [spaces_usage_collector.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/server/usage_collection/spaces_usage_collector.ts#:~:text=getKibanaFeatures), [on_post_auth_interceptor.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts#:~:text=getKibanaFeatures) | 8.8.0 | +| | [on_post_auth_interceptor.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts#:~:text=getKibanaFeatures), [spaces_usage_collector.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/server/usage_collection/spaces_usage_collector.ts#:~:text=getKibanaFeatures), [on_post_auth_interceptor.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts#:~:text=getKibanaFeatures) | 8.8.0 | | | [spaces_usage_collector.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/server/usage_collection/spaces_usage_collector.ts#:~:text=license%24), [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/server/plugin.ts#:~:text=license%24), [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/server/plugin.ts#:~:text=license%24), [spaces_usage_collector.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/server/usage_collection/spaces_usage_collector.test.ts#:~:text=license%24) | 8.8.0 | | | [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/public/legacy_urls/types.ts#:~:text=ResolvedSimpleSavedObject), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/public/legacy_urls/types.ts#:~:text=ResolvedSimpleSavedObject) | - | | | [copy_to_space_flyout_internal.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_to_space_flyout_internal.tsx#:~:text=createNewCopy) | - | diff --git a/api_docs/deprecations_by_team.mdx b/api_docs/deprecations_by_team.mdx index 57a78fd050371..f9451cf5c2752 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -79,7 +79,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Plugin | Deprecated API | Reference location(s) | Remove By | | --------|-------|-----------|-----------| -| spaces | | [on_post_auth_interceptor.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts#:~:text=getKibanaFeatures), [spaces_usage_collector.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/server/usage_collection/spaces_usage_collector.ts#:~:text=getKibanaFeatures), [on_post_auth_interceptor.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts#:~:text=getKibanaFeatures), [app_authorization.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/app_authorization.ts#:~:text=getKibanaFeatures), [privileges.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.ts#:~:text=getKibanaFeatures), [authorization_service.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/authorization_service.tsx#:~:text=getKibanaFeatures), [app_authorization.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/app_authorization.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts#:~:text=getKibanaFeatures)+ 27 more | 8.8.0 | +| spaces | | [on_post_auth_interceptor.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts#:~:text=getKibanaFeatures), [spaces_usage_collector.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/server/usage_collection/spaces_usage_collector.ts#:~:text=getKibanaFeatures), [on_post_auth_interceptor.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts#:~:text=getKibanaFeatures), [app_authorization.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/app_authorization.ts#:~:text=getKibanaFeatures), [privileges.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.ts#:~:text=getKibanaFeatures), [authorization_service.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/authorization_service.tsx#:~:text=getKibanaFeatures), [app_authorization.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/app_authorization.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts#:~:text=getKibanaFeatures), [privileges.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts#:~:text=getKibanaFeatures)+ 27 more | 8.8.0 | | spaces | | [spaces_usage_collector.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/server/usage_collection/spaces_usage_collector.ts#:~:text=license%24), [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/server/plugin.ts#:~:text=license%24), [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/server/plugin.ts#:~:text=license%24), [spaces_usage_collector.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/spaces/server/usage_collection/spaces_usage_collector.test.ts#:~:text=license%24), [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/plugin.ts#:~:text=license%24) | 8.8.0 | | security | | [disable_ui_capabilities.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/disable_ui_capabilities.ts#:~:text=requiredRoles) | 8.8.0 @@ -89,7 +89,7 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ This is relied on by the reporting feature, and should be removed once reporting migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/issues/19914 | -| security | | [authorization_service.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/authorization_service.tsx#:~:text=getElasticsearchFeatures) | 8.8.0 | +| security | | [authorization_service.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/server/authorization/authorization_service.tsx#:~:text=getElasticsearchFeatures) | 8.8.0 | | security | | [license_service.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/common/licensing/license_service.test.ts#:~:text=mode), [license_service.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/common/licensing/license_service.test.ts#:~:text=mode), [license_service.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/common/licensing/license_service.test.ts#:~:text=mode) | 8.8.0 | | security | | [plugin.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/public/plugin.tsx#:~:text=license%24) | 8.8.0 | | security | | [license_service.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/common/licensing/license_service.test.ts#:~:text=mode), [license_service.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/common/licensing/license_service.test.ts#:~:text=mode), [license_service.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security/common/licensing/license_service.test.ts#:~:text=mode) | 8.8.0 | @@ -146,7 +146,7 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | Plugin | Deprecated API | Reference location(s) | Remove By | | --------|-------|-----------|-----------| -| alerting | | [plugin.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/plugin.test.ts#:~:text=getKibanaFeatures), [factory.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cases/server/client/factory.test.ts#:~:text=getKibanaFeatures) | 8.8.0 | +| alerting | | [plugin.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/plugin.test.ts#:~:text=getKibanaFeatures), [factory.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cases/server/client/factory.test.ts#:~:text=getKibanaFeatures) | 8.8.0 | | alerting | | [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/plugin.ts#:~:text=license%24), [license_state.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/lib/license_state.test.ts#:~:text=license%24), [license_state.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/alerting/server/lib/license_state.test.ts#:~:text=license%24), [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/plugin.ts#:~:text=license%24), [license_state.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/lib/license_state.test.ts#:~:text=license%24), [license_state.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/actions/server/lib/license_state.test.ts#:~:text=license%24) | 8.8.0 | diff --git a/api_docs/dev_tools.mdx b/api_docs/dev_tools.mdx index 014cf8aa5d9c8..395c163b95e46 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-07-17 +date: 2024-07-19 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 2d5760339f296..b4dbd0fdea29f 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-07-17 +date: 2024-07-19 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 6860d47be33c1..7411a87f4539e 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-07-17 +date: 2024-07-19 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 3d32d2b6e4921..714e1572241d9 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-07-17 +date: 2024-07-19 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 1d1b6a787c793..ee363b49b2dc4 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-07-17 +date: 2024-07-19 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 a792d44c94558..287fa396d44cb 100644 --- a/api_docs/elastic_assistant.devdocs.json +++ b/api_docs/elastic_assistant.devdocs.json @@ -1609,7 +1609,7 @@ "section": "def-common.KibanaRequest", "text": "KibanaRequest" }, - " | undefined; }, any>" + " | undefined; }, any>" ], "path": "x-pack/plugins/elastic_assistant/server/types.ts", "deprecated": false, diff --git a/api_docs/elastic_assistant.mdx b/api_docs/elastic_assistant.mdx index 2448a50b5848c..3ddd435c24a81 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'elasticAssistant'] --- import elasticAssistantObj from './elastic_assistant.devdocs.json'; diff --git a/api_docs/embeddable.mdx b/api_docs/embeddable.mdx index 09f1f5a6785bb..ae930a9673dff 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-07-17 +date: 2024-07-19 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 e95a1dfb8766f..052f287b9eb5c 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-07-17 +date: 2024-07-19 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 33630527f3dc2..6fa3c845341b3 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-07-17 +date: 2024-07-19 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 255acc68198a4..6209076811a8a 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'enterpriseSearch'] --- import enterpriseSearchObj from './enterprise_search.devdocs.json'; diff --git a/api_docs/entity_manager.mdx b/api_docs/entity_manager.mdx index 3a1b935e84afe..258897eed05d9 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-07-17 +date: 2024-07-19 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 17c748e18810a..cff9bb046d0b5 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esUiShared'] --- import esUiSharedObj from './es_ui_shared.devdocs.json'; diff --git a/api_docs/esql.devdocs.json b/api_docs/esql.devdocs.json index f3d9e7db3931c..34e545084895c 100644 --- a/api_docs/esql.devdocs.json +++ b/api_docs/esql.devdocs.json @@ -284,15 +284,15 @@ }, { "parentPluginId": "esql", - "id": "def-public.TextBasedLanguagesEditorProps.detectTimestamp", - "type": "CompoundType", + "id": "def-public.TextBasedLanguagesEditorProps.detectedTimestamp", + "type": "string", "tags": [], - "label": "detectTimestamp", + "label": "detectedTimestamp", "description": [ "If it is true, the editor displays the message @timestamp found\nThe text based queries are relying on adhoc dataviews which\ncan have an @timestamp timefield or nothing" ], "signature": [ - "boolean | undefined" + "string | undefined" ], "path": "packages/kbn-text-based-editor/src/text_based_languages_editor.tsx", "deprecated": false, diff --git a/api_docs/esql.mdx b/api_docs/esql.mdx index c2724459d3d00..6c8b18bbbbd5b 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-07-17 +date: 2024-07-19 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 c7a78a3733523..4a222644de987 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-07-17 +date: 2024-07-19 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 0f8093844a9a6..4de8c06814fd7 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-07-17 +date: 2024-07-19 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 47872a66c977f..6ee4ab1135593 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-07-17 +date: 2024-07-19 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 5d91274342c40..e5c57f7b73014 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-07-17 +date: 2024-07-19 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 0aedba65e8375..8f50381c83996 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-07-17 +date: 2024-07-19 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 45d1eb2127055..8d7cf220a5df6 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-07-17 +date: 2024-07-19 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 704c92d430a89..a0920f3feb011 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-07-17 +date: 2024-07-19 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 1a12acd961cc2..2336e2381e885 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-07-17 +date: 2024-07-19 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 76e1482292cb0..0c9cc8377c88d 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-07-17 +date: 2024-07-19 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 4c77799a0a8cd..a25d578984d5b 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-07-17 +date: 2024-07-19 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 379b587ef635b..0c591578db862 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-07-17 +date: 2024-07-19 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 a4cb5ece6be71..db12f47f5d59a 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-07-17 +date: 2024-07-19 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 2aa4c1eab1a91..692437c488579 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-07-17 +date: 2024-07-19 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 e58d6fb0e6dde..2a547cf12b79b 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-07-17 +date: 2024-07-19 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 525c6273a8bc7..c815f1aa67590 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-07-17 +date: 2024-07-19 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 8f3ab49d1a1bc..daead156dd8ee 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-07-17 +date: 2024-07-19 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 ed687fc8e6b05..565084399418d 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-07-17 +date: 2024-07-19 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 e5f921f8903fc..fcb96122aa267 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionXY'] --- import expressionXYObj from './expression_x_y.devdocs.json'; diff --git a/api_docs/expressions.devdocs.json b/api_docs/expressions.devdocs.json index 9f91694efe0cf..646439bc16dde 100644 --- a/api_docs/expressions.devdocs.json +++ b/api_docs/expressions.devdocs.json @@ -29469,13 +29469,13 @@ }, { "parentPluginId": "expressions", - "id": "def-common.getUiSettingFn", + "id": "def-common.getUiSettingFnBrowser", "type": "Function", "tags": [], - "label": "getUiSettingFn", + "label": "getUiSettingFnBrowser", "description": [], "signature": [ - "({\n getStartDependencies,\n}: UiSettingFnArguments) => ", + "({\n getStartDependencies,\n}: UiSettingFnArgumentsBrowser) => ", { "pluginId": "expressions", "scope": "common", @@ -29490,13 +29490,53 @@ "children": [ { "parentPluginId": "expressions", - "id": "def-common.getUiSettingFn.$1", + "id": "def-common.getUiSettingFnBrowser.$1", "type": "Object", "tags": [], "label": "{\n getStartDependencies,\n}", "description": [], "signature": [ - "UiSettingFnArguments" + "UiSettingFnArgumentsBrowser" + ], + "path": "src/plugins/expressions/common/expression_functions/specs/ui_setting.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "expressions", + "id": "def-common.getUiSettingFnServer", + "type": "Function", + "tags": [], + "label": "getUiSettingFnServer", + "description": [], + "signature": [ + "({\n getStartDependencies,\n}: UiSettingFnArgumentsServer) => ", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.ExpressionFunctionUiSetting", + "text": "ExpressionFunctionUiSetting" + } + ], + "path": "src/plugins/expressions/common/expression_functions/specs/ui_setting.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "expressions", + "id": "def-common.getUiSettingFnServer.$1", + "type": "Object", + "tags": [], + "label": "{\n getStartDependencies,\n}", + "description": [], + "signature": [ + "UiSettingFnArgumentsServer" ], "path": "src/plugins/expressions/common/expression_functions/specs/ui_setting.ts", "deprecated": false, diff --git a/api_docs/expressions.mdx b/api_docs/expressions.mdx index bda7099e83687..9df0a986056b2 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressions'] --- import expressionsObj from './expressions.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 | |-------------------|-----------|------------------------|-----------------| -| 2233 | 17 | 1763 | 6 | +| 2235 | 17 | 1765 | 6 | ## Client diff --git a/api_docs/features.devdocs.json b/api_docs/features.devdocs.json index 9af80b8a01f04..e6c5019a037fb 100644 --- a/api_docs/features.devdocs.json +++ b/api_docs/features.devdocs.json @@ -1965,448 +1965,130 @@ }, { "parentPluginId": "features", - "id": "def-server.KibanaFeatureConfig", + "id": "def-server.FeaturesPluginSetup", "type": "Interface", "tags": [], - "label": "KibanaFeatureConfig", + "label": "FeaturesPluginSetup", "description": [ - "\nInterface for registering a feature.\nFeature registration allows plugins to hide their applications with spaces,\nand secure access when configured for security." + "\nDescribes public Features plugin contract returned at the `setup` stage." ], - "path": "x-pack/plugins/features/common/kibana_feature.ts", + "path": "x-pack/plugins/features/server/plugin.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "features", - "id": "def-server.KibanaFeatureConfig.id", - "type": "string", - "tags": [ - "see" - ], - "label": "id", - "description": [ - "\nUnique identifier for this feature.\nThis identifier is also used when generating UI Capabilities.\n" - ], - "path": "x-pack/plugins/features/common/kibana_feature.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "features", - "id": "def-server.KibanaFeatureConfig.name", - "type": "string", - "tags": [], - "label": "name", - "description": [ - "\nDisplay name for this feature.\nThis will be displayed to end-users, so a translatable string is advised for i18n." - ], - "path": "x-pack/plugins/features/common/kibana_feature.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "features", - "id": "def-server.KibanaFeatureConfig.description", - "type": "string", - "tags": [], - "label": "description", - "description": [ - "\nAn optional description that will appear as subtext underneath the feature name" - ], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/features/common/kibana_feature.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "features", - "id": "def-server.KibanaFeatureConfig.category", - "type": "Object", + "id": "def-server.FeaturesPluginSetup.registerKibanaFeature", + "type": "Function", "tags": [], - "label": "category", - "description": [ - "\nThe category for this feature.\nThis will be used to organize the list of features for display within the\nSpaces and Roles management screens." - ], + "label": "registerKibanaFeature", + "description": [], "signature": [ + "(feature: ", { - "pluginId": "@kbn/core-application-common", + "pluginId": "features", "scope": "common", - "docId": "kibKbnCoreApplicationCommonPluginApi", - "section": "def-common.AppCategory", - "text": "AppCategory" - } - ], - "path": "x-pack/plugins/features/common/kibana_feature.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "features", - "id": "def-server.KibanaFeatureConfig.order", - "type": "number", - "tags": [], - "label": "order", - "description": [ - "\nAn ordinal used to sort features relative to one another for display." - ], - "signature": [ - "number | undefined" - ], - "path": "x-pack/plugins/features/common/kibana_feature.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "features", - "id": "def-server.KibanaFeatureConfig.excludeFromBasePrivileges", - "type": "CompoundType", - "tags": [], - "label": "excludeFromBasePrivileges", - "description": [ - "\nWhether or not this feature should be excluded from the base privileges.\nThis is primarily helpful when migrating applications with a \"legacy\" privileges model\nto use Kibana privileges. We don't want these features to be considered part of the `all`\nor `read` base privileges in a minor release if the user was previously granted access\nusing an additional reserved role." - ], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/plugins/features/common/kibana_feature.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "features", - "id": "def-server.KibanaFeatureConfig.minimumLicense", - "type": "CompoundType", - "tags": [], - "label": "minimumLicense", - "description": [ - "\nOptional minimum supported license.\nIf omitted, all licenses are allowed.\nThis does not restrict access to your feature based on license.\nIts only purpose is to inform the space and roles UIs on which features to display." - ], - "signature": [ - "\"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined" + "docId": "kibFeaturesPluginApi", + "section": "def-common.KibanaFeatureConfig", + "text": "KibanaFeatureConfig" + }, + ") => void" ], - "path": "x-pack/plugins/features/common/kibana_feature.ts", + "path": "x-pack/plugins/features/server/plugin.ts", "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "features", - "id": "def-server.KibanaFeatureConfig.app", - "type": "Object", - "tags": [], - "label": "app", - "description": [ - "\nAn array of app ids that are enabled when this feature is enabled.\nApps specified here will automatically cascade to the privileges defined below, unless specified differently there." - ], - "signature": [ - "readonly string[]" + "trackAdoption": false, + "children": [ + { + "parentPluginId": "features", + "id": "def-server.FeaturesPluginSetup.registerKibanaFeature.$1", + "type": "Object", + "tags": [], + "label": "feature", + "description": [], + "signature": [ + { + "pluginId": "features", + "scope": "common", + "docId": "kibFeaturesPluginApi", + "section": "def-common.KibanaFeatureConfig", + "text": "KibanaFeatureConfig" + } + ], + "path": "x-pack/plugins/features/server/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } ], - "path": "x-pack/plugins/features/common/kibana_feature.ts", - "deprecated": false, - "trackAdoption": false + "returnComment": [] }, { "parentPluginId": "features", - "id": "def-server.KibanaFeatureConfig.management", - "type": "Object", + "id": "def-server.FeaturesPluginSetup.registerElasticsearchFeature", + "type": "Function", "tags": [], - "label": "management", - "description": [ - "\nIf this feature includes management sections, you can specify them here to control visibility of those\npages based on the current space.\n\nItems specified here will automatically cascade to the privileges defined below, unless specified differently there.\n" - ], + "label": "registerElasticsearchFeature", + "description": [], "signature": [ - "{ [sectionId: string]: readonly string[]; } | undefined" + "(feature: ", + { + "pluginId": "features", + "scope": "common", + "docId": "kibFeaturesPluginApi", + "section": "def-common.ElasticsearchFeatureConfig", + "text": "ElasticsearchFeatureConfig" + }, + ") => void" ], - "path": "x-pack/plugins/features/common/kibana_feature.ts", + "path": "x-pack/plugins/features/server/plugin.ts", "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "features", - "id": "def-server.KibanaFeatureConfig.catalogue", - "type": "Object", - "tags": [], - "label": "catalogue", - "description": [ - "\nIf this feature includes a catalogue entry, you can specify them here to control visibility based on the current space.\n\nItems specified here will automatically cascade to the privileges defined below, unless specified differently there." - ], - "signature": [ - "readonly string[] | undefined" + "trackAdoption": false, + "children": [ + { + "parentPluginId": "features", + "id": "def-server.FeaturesPluginSetup.registerElasticsearchFeature.$1", + "type": "Object", + "tags": [], + "label": "feature", + "description": [], + "signature": [ + { + "pluginId": "features", + "scope": "common", + "docId": "kibFeaturesPluginApi", + "section": "def-common.ElasticsearchFeatureConfig", + "text": "ElasticsearchFeatureConfig" + } + ], + "path": "x-pack/plugins/features/server/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } ], - "path": "x-pack/plugins/features/common/kibana_feature.ts", - "deprecated": false, - "trackAdoption": false + "returnComment": [] }, { "parentPluginId": "features", - "id": "def-server.KibanaFeatureConfig.alerting", - "type": "Object", - "tags": [], - "label": "alerting", - "description": [ - "\nIf your feature grants access to specific Alert Types, you can specify them here to control visibility based on the current space.\nInclude both Alert Types registered by the feature and external Alert Types such as built-in\nAlert Types and Alert Types provided by other features to which you wish to grant access." - ], - "signature": [ - "readonly string[] | undefined" + "id": "def-server.FeaturesPluginSetup.getKibanaFeatures", + "type": "Function", + "tags": [ + "deprecated" ], - "path": "x-pack/plugins/features/common/kibana_feature.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "features", - "id": "def-server.KibanaFeatureConfig.cases", - "type": "Object", - "tags": [], - "label": "cases", + "label": "getKibanaFeatures", "description": [ - "\nIf your feature grants access to specific case types, you can specify them here to control visibility based on the current space." + "\nCalling this function during setup will crash Kibana.\nUse start contract instead." ], "signature": [ - "readonly string[] | undefined" - ], - "path": "x-pack/plugins/features/common/kibana_feature.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "features", - "id": "def-server.KibanaFeatureConfig.privileges", - "type": "CompoundType", - "tags": [ - "see" - ], - "label": "privileges", - "description": [ - "\nFeature privilege definition.\n" - ], - "signature": [ - "{ all: ", - { - "pluginId": "features", - "scope": "common", - "docId": "kibFeaturesPluginApi", - "section": "def-common.FeatureKibanaPrivileges", - "text": "FeatureKibanaPrivileges" - }, - "; read: ", - { - "pluginId": "features", - "scope": "common", - "docId": "kibFeaturesPluginApi", - "section": "def-common.FeatureKibanaPrivileges", - "text": "FeatureKibanaPrivileges" - }, - "; } | null" - ], - "path": "x-pack/plugins/features/common/kibana_feature.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "features", - "id": "def-server.KibanaFeatureConfig.subFeatures", - "type": "Object", - "tags": [], - "label": "subFeatures", - "description": [ - "\nOptional sub-feature privilege definitions. This can only be specified if `privileges` are are also defined." - ], - "signature": [ - "readonly ", - { - "pluginId": "features", - "scope": "common", - "docId": "kibFeaturesPluginApi", - "section": "def-common.SubFeatureConfig", - "text": "SubFeatureConfig" - }, - "[] | undefined" - ], - "path": "x-pack/plugins/features/common/kibana_feature.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "features", - "id": "def-server.KibanaFeatureConfig.privilegesTooltip", - "type": "string", - "tags": [], - "label": "privilegesTooltip", - "description": [ - "\nOptional message to display on the Role Management screen when configuring permissions for this feature." - ], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/features/common/kibana_feature.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "features", - "id": "def-server.KibanaFeatureConfig.reserved", - "type": "Object", - "tags": [ - "private" - ], - "label": "reserved", - "description": [], - "signature": [ - "{ description: string; privileges: readonly ", - "ReservedKibanaPrivilege", - "[]; } | undefined" - ], - "path": "x-pack/plugins/features/common/kibana_feature.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "features", - "id": "def-server.KibanaFeatureConfig.hidden", - "type": "CompoundType", - "tags": [], - "label": "hidden", - "description": [ - "\nIndicates whether the feature is available as a standalone feature. The feature can still be\nreferenced by other features, but it will not be displayed in any feature management UIs. By default, all features\nare visible." - ], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/plugins/features/common/kibana_feature.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "features", - "id": "def-server.PluginSetupContract", - "type": "Interface", - "tags": [], - "label": "PluginSetupContract", - "description": [ - "\nDescribes public Features plugin contract returned at the `setup` stage." - ], - "path": "x-pack/plugins/features/server/plugin.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "features", - "id": "def-server.PluginSetupContract.registerKibanaFeature", - "type": "Function", - "tags": [], - "label": "registerKibanaFeature", - "description": [], - "signature": [ - "(feature: ", - { - "pluginId": "features", - "scope": "common", - "docId": "kibFeaturesPluginApi", - "section": "def-common.KibanaFeatureConfig", - "text": "KibanaFeatureConfig" - }, - ") => void" - ], - "path": "x-pack/plugins/features/server/plugin.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "features", - "id": "def-server.PluginSetupContract.registerKibanaFeature.$1", - "type": "Object", - "tags": [], - "label": "feature", - "description": [], - "signature": [ - { - "pluginId": "features", - "scope": "common", - "docId": "kibFeaturesPluginApi", - "section": "def-common.KibanaFeatureConfig", - "text": "KibanaFeatureConfig" - } - ], - "path": "x-pack/plugins/features/server/plugin.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "features", - "id": "def-server.PluginSetupContract.registerElasticsearchFeature", - "type": "Function", - "tags": [], - "label": "registerElasticsearchFeature", - "description": [], - "signature": [ - "(feature: ", - { - "pluginId": "features", - "scope": "common", - "docId": "kibFeaturesPluginApi", - "section": "def-common.ElasticsearchFeatureConfig", - "text": "ElasticsearchFeatureConfig" - }, - ") => void" - ], - "path": "x-pack/plugins/features/server/plugin.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "features", - "id": "def-server.PluginSetupContract.registerElasticsearchFeature.$1", - "type": "Object", - "tags": [], - "label": "feature", - "description": [], - "signature": [ - { - "pluginId": "features", - "scope": "common", - "docId": "kibFeaturesPluginApi", - "section": "def-common.ElasticsearchFeatureConfig", - "text": "ElasticsearchFeatureConfig" - } - ], - "path": "x-pack/plugins/features/server/plugin.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "features", - "id": "def-server.PluginSetupContract.getKibanaFeatures", - "type": "Function", - "tags": [ - "deprecated" - ], - "label": "getKibanaFeatures", - "description": [ - "\nCalling this function during setup will crash Kibana.\nUse start contract instead." - ], - "signature": [ - "() => ", - { - "pluginId": "features", - "scope": "common", - "docId": "kibFeaturesPluginApi", - "section": "def-common.KibanaFeature", - "text": "KibanaFeature" - }, - "[]" + "() => ", + { + "pluginId": "features", + "scope": "common", + "docId": "kibFeaturesPluginApi", + "section": "def-common.KibanaFeature", + "text": "KibanaFeature" + }, + "[]" ], "path": "x-pack/plugins/features/server/plugin.ts", "deprecated": true, @@ -2575,7 +2257,7 @@ }, { "parentPluginId": "features", - "id": "def-server.PluginSetupContract.getElasticsearchFeatures", + "id": "def-server.FeaturesPluginSetup.getElasticsearchFeatures", "type": "Function", "tags": [ "deprecated" @@ -2605,48 +2287,477 @@ "path": "x-pack/plugins/security/server/authorization/authorization_service.tsx" } ], - "children": [], - "returnComment": [] + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "features", + "id": "def-server.FeaturesPluginSetup.enableReportingUiCapabilities", + "type": "Function", + "tags": [], + "label": "enableReportingUiCapabilities", + "description": [ + "\nIn the future, OSS features should register their own subfeature\nprivileges. This can be done when parts of Reporting are moved to\nsrc/plugins. For now, this method exists for `reporting` to tell\n`features` to include Reporting when registering OSS features." + ], + "signature": [ + "() => void" + ], + "path": "x-pack/plugins/features/server/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "features", + "id": "def-server.FeaturesPluginSetup.featurePrivilegeIterator", + "type": "Function", + "tags": [], + "label": "featurePrivilegeIterator", + "description": [ + "\nUtility for iterating through all privileges belonging to a specific feature.\n{@see FeaturePrivilegeIterator }" + ], + "signature": [ + "(feature: ", + { + "pluginId": "features", + "scope": "common", + "docId": "kibFeaturesPluginApi", + "section": "def-common.KibanaFeature", + "text": "KibanaFeature" + }, + ", options: ", + "FeaturePrivilegeIteratorOptions", + ") => IterableIterator<{ privilegeId: string; privilege: ", + { + "pluginId": "features", + "scope": "common", + "docId": "kibFeaturesPluginApi", + "section": "def-common.FeatureKibanaPrivileges", + "text": "FeatureKibanaPrivileges" + }, + "; }>" + ], + "path": "x-pack/plugins/features/server/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "features", + "id": "def-server.FeaturesPluginSetup.featurePrivilegeIterator.$1", + "type": "Object", + "tags": [], + "label": "feature", + "description": [], + "signature": [ + { + "pluginId": "features", + "scope": "common", + "docId": "kibFeaturesPluginApi", + "section": "def-common.KibanaFeature", + "text": "KibanaFeature" + } + ], + "path": "x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "features", + "id": "def-server.FeaturesPluginSetup.featurePrivilegeIterator.$2", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "FeaturePrivilegeIteratorOptions" + ], + "path": "x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "features", + "id": "def-server.FeaturesPluginSetup.subFeaturePrivilegeIterator", + "type": "Function", + "tags": [], + "label": "subFeaturePrivilegeIterator", + "description": [ + "\nUtility for iterating through all sub-feature privileges belonging to a specific feature.\n{@see SubFeaturePrivilegeIterator }" + ], + "signature": [ + "(feature: ", + { + "pluginId": "features", + "scope": "common", + "docId": "kibFeaturesPluginApi", + "section": "def-common.KibanaFeature", + "text": "KibanaFeature" + }, + ", licenseHasAtLeast: (licenseType: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\") => boolean | undefined) => IterableIterator<", + { + "pluginId": "features", + "scope": "common", + "docId": "kibFeaturesPluginApi", + "section": "def-common.SubFeaturePrivilegeConfig", + "text": "SubFeaturePrivilegeConfig" + }, + ">" + ], + "path": "x-pack/plugins/features/server/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "features", + "id": "def-server.FeaturesPluginSetup.subFeaturePrivilegeIterator.$1", + "type": "Object", + "tags": [], + "label": "feature", + "description": [], + "signature": [ + { + "pluginId": "features", + "scope": "common", + "docId": "kibFeaturesPluginApi", + "section": "def-common.KibanaFeature", + "text": "KibanaFeature" + } + ], + "path": "x-pack/plugins/features/server/feature_privilege_iterator/sub_feature_privilege_iterator.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "features", + "id": "def-server.FeaturesPluginSetup.subFeaturePrivilegeIterator.$2", + "type": "Function", + "tags": [], + "label": "licenseHasAtLeast", + "description": [], + "signature": [ + "(licenseType: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\") => boolean | undefined" + ], + "path": "x-pack/plugins/features/server/feature_privilege_iterator/sub_feature_privilege_iterator.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "features", + "id": "def-server.FeaturesPluginSetup.subFeaturePrivilegeIterator.$2.$1", + "type": "CompoundType", + "tags": [], + "label": "licenseType", + "description": [], + "signature": [ + "\"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\"" + ], + "path": "x-pack/plugins/features/server/feature_privilege_iterator/sub_feature_privilege_iterator.ts", + "deprecated": false, + "trackAdoption": false + } + ] + } + ] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "features", + "id": "def-server.FeaturesPluginStart", + "type": "Interface", + "tags": [], + "label": "FeaturesPluginStart", + "description": [], + "path": "x-pack/plugins/features/server/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "features", + "id": "def-server.FeaturesPluginStart.getElasticsearchFeatures", + "type": "Function", + "tags": [], + "label": "getElasticsearchFeatures", + "description": [], + "signature": [ + "() => ", + { + "pluginId": "features", + "scope": "common", + "docId": "kibFeaturesPluginApi", + "section": "def-common.ElasticsearchFeature", + "text": "ElasticsearchFeature" + }, + "[]" + ], + "path": "x-pack/plugins/features/server/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "features", + "id": "def-server.FeaturesPluginStart.getKibanaFeatures", + "type": "Function", + "tags": [], + "label": "getKibanaFeatures", + "description": [], + "signature": [ + "() => ", + { + "pluginId": "features", + "scope": "common", + "docId": "kibFeaturesPluginApi", + "section": "def-common.KibanaFeature", + "text": "KibanaFeature" + }, + "[]" + ], + "path": "x-pack/plugins/features/server/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "features", + "id": "def-server.KibanaFeatureConfig", + "type": "Interface", + "tags": [], + "label": "KibanaFeatureConfig", + "description": [ + "\nInterface for registering a feature.\nFeature registration allows plugins to hide their applications with spaces,\nand secure access when configured for security." + ], + "path": "x-pack/plugins/features/common/kibana_feature.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "features", + "id": "def-server.KibanaFeatureConfig.id", + "type": "string", + "tags": [ + "see" + ], + "label": "id", + "description": [ + "\nUnique identifier for this feature.\nThis identifier is also used when generating UI Capabilities.\n" + ], + "path": "x-pack/plugins/features/common/kibana_feature.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "features", + "id": "def-server.KibanaFeatureConfig.name", + "type": "string", + "tags": [], + "label": "name", + "description": [ + "\nDisplay name for this feature.\nThis will be displayed to end-users, so a translatable string is advised for i18n." + ], + "path": "x-pack/plugins/features/common/kibana_feature.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "features", + "id": "def-server.KibanaFeatureConfig.description", + "type": "string", + "tags": [], + "label": "description", + "description": [ + "\nAn optional description that will appear as subtext underneath the feature name" + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/features/common/kibana_feature.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "features", + "id": "def-server.KibanaFeatureConfig.category", + "type": "Object", + "tags": [], + "label": "category", + "description": [ + "\nThe category for this feature.\nThis will be used to organize the list of features for display within the\nSpaces and Roles management screens." + ], + "signature": [ + { + "pluginId": "@kbn/core-application-common", + "scope": "common", + "docId": "kibKbnCoreApplicationCommonPluginApi", + "section": "def-common.AppCategory", + "text": "AppCategory" + } + ], + "path": "x-pack/plugins/features/common/kibana_feature.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "features", + "id": "def-server.KibanaFeatureConfig.order", + "type": "number", + "tags": [], + "label": "order", + "description": [ + "\nAn ordinal used to sort features relative to one another for display." + ], + "signature": [ + "number | undefined" + ], + "path": "x-pack/plugins/features/common/kibana_feature.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "features", + "id": "def-server.KibanaFeatureConfig.excludeFromBasePrivileges", + "type": "CompoundType", + "tags": [], + "label": "excludeFromBasePrivileges", + "description": [ + "\nWhether or not this feature should be excluded from the base privileges.\nThis is primarily helpful when migrating applications with a \"legacy\" privileges model\nto use Kibana privileges. We don't want these features to be considered part of the `all`\nor `read` base privileges in a minor release if the user was previously granted access\nusing an additional reserved role." + ], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/features/common/kibana_feature.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "features", + "id": "def-server.KibanaFeatureConfig.minimumLicense", + "type": "CompoundType", + "tags": [], + "label": "minimumLicense", + "description": [ + "\nOptional minimum supported license.\nIf omitted, all licenses are allowed.\nThis does not restrict access to your feature based on license.\nIts only purpose is to inform the space and roles UIs on which features to display." + ], + "signature": [ + "\"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined" + ], + "path": "x-pack/plugins/features/common/kibana_feature.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "features", + "id": "def-server.KibanaFeatureConfig.app", + "type": "Object", + "tags": [], + "label": "app", + "description": [ + "\nAn array of app ids that are enabled when this feature is enabled.\nApps specified here will automatically cascade to the privileges defined below, unless specified differently there." + ], + "signature": [ + "readonly string[]" + ], + "path": "x-pack/plugins/features/common/kibana_feature.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "features", + "id": "def-server.KibanaFeatureConfig.management", + "type": "Object", + "tags": [], + "label": "management", + "description": [ + "\nIf this feature includes management sections, you can specify them here to control visibility of those\npages based on the current space.\n\nItems specified here will automatically cascade to the privileges defined below, unless specified differently there.\n" + ], + "signature": [ + "{ [sectionId: string]: readonly string[]; } | undefined" + ], + "path": "x-pack/plugins/features/common/kibana_feature.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "features", + "id": "def-server.KibanaFeatureConfig.catalogue", + "type": "Object", + "tags": [], + "label": "catalogue", + "description": [ + "\nIf this feature includes a catalogue entry, you can specify them here to control visibility based on the current space.\n\nItems specified here will automatically cascade to the privileges defined below, unless specified differently there." + ], + "signature": [ + "readonly string[] | undefined" + ], + "path": "x-pack/plugins/features/common/kibana_feature.ts", + "deprecated": false, + "trackAdoption": false }, { "parentPluginId": "features", - "id": "def-server.PluginSetupContract.enableReportingUiCapabilities", - "type": "Function", + "id": "def-server.KibanaFeatureConfig.alerting", + "type": "Object", "tags": [], - "label": "enableReportingUiCapabilities", + "label": "alerting", "description": [ - "\nIn the future, OSS features should register their own subfeature\nprivileges. This can be done when parts of Reporting are moved to\nsrc/plugins. For now, this method exists for `reporting` to tell\n`features` to include Reporting when registering OSS features." + "\nIf your feature grants access to specific Alert Types, you can specify them here to control visibility based on the current space.\nInclude both Alert Types registered by the feature and external Alert Types such as built-in\nAlert Types and Alert Types provided by other features to which you wish to grant access." ], "signature": [ - "() => void" + "readonly string[] | undefined" ], - "path": "x-pack/plugins/features/server/plugin.ts", + "path": "x-pack/plugins/features/common/kibana_feature.ts", "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] + "trackAdoption": false }, { "parentPluginId": "features", - "id": "def-server.PluginSetupContract.featurePrivilegeIterator", - "type": "Function", + "id": "def-server.KibanaFeatureConfig.cases", + "type": "Object", "tags": [], - "label": "featurePrivilegeIterator", + "label": "cases", "description": [ - "\nUtility for iterating through all privileges belonging to a specific feature.\n{@see FeaturePrivilegeIterator }" + "\nIf your feature grants access to specific case types, you can specify them here to control visibility based on the current space." ], "signature": [ - "(feature: ", + "readonly string[] | undefined" + ], + "path": "x-pack/plugins/features/common/kibana_feature.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "features", + "id": "def-server.KibanaFeatureConfig.privileges", + "type": "CompoundType", + "tags": [ + "see" + ], + "label": "privileges", + "description": [ + "\nFeature privilege definition.\n" + ], + "signature": [ + "{ all: ", { "pluginId": "features", "scope": "common", "docId": "kibFeaturesPluginApi", - "section": "def-common.KibanaFeature", - "text": "KibanaFeature" + "section": "def-common.FeatureKibanaPrivileges", + "text": "FeatureKibanaPrivileges" }, - ", options: ", - "FeaturePrivilegeIteratorOptions", - ") => IterableIterator<{ privilegeId: string; privilege: ", + "; read: ", { "pluginId": "features", "scope": "common", @@ -2654,196 +2765,85 @@ "section": "def-common.FeatureKibanaPrivileges", "text": "FeatureKibanaPrivileges" }, - "; }>" + "; } | null" ], - "path": "x-pack/plugins/features/server/plugin.ts", + "path": "x-pack/plugins/features/common/kibana_feature.ts", "deprecated": false, - "trackAdoption": false, - "returnComment": [], - "children": [ - { - "parentPluginId": "features", - "id": "def-server.PluginSetupContract.featurePrivilegeIterator.$1", - "type": "Object", - "tags": [], - "label": "feature", - "description": [], - "signature": [ - { - "pluginId": "features", - "scope": "common", - "docId": "kibFeaturesPluginApi", - "section": "def-common.KibanaFeature", - "text": "KibanaFeature" - } - ], - "path": "x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "features", - "id": "def-server.PluginSetupContract.featurePrivilegeIterator.$2", - "type": "Object", - "tags": [], - "label": "options", - "description": [], - "signature": [ - "FeaturePrivilegeIteratorOptions" - ], - "path": "x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.ts", - "deprecated": false, - "trackAdoption": false - } - ] + "trackAdoption": false }, { "parentPluginId": "features", - "id": "def-server.PluginSetupContract.subFeaturePrivilegeIterator", - "type": "Function", + "id": "def-server.KibanaFeatureConfig.subFeatures", + "type": "Object", "tags": [], - "label": "subFeaturePrivilegeIterator", + "label": "subFeatures", "description": [ - "\nUtility for iterating through all sub-feature privileges belonging to a specific feature.\n{@see SubFeaturePrivilegeIterator }" + "\nOptional sub-feature privilege definitions. This can only be specified if `privileges` are are also defined." ], "signature": [ - "(feature: ", - { - "pluginId": "features", - "scope": "common", - "docId": "kibFeaturesPluginApi", - "section": "def-common.KibanaFeature", - "text": "KibanaFeature" - }, - ", licenseHasAtLeast: (licenseType: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\") => boolean | undefined) => IterableIterator<", + "readonly ", { "pluginId": "features", "scope": "common", "docId": "kibFeaturesPluginApi", - "section": "def-common.SubFeaturePrivilegeConfig", - "text": "SubFeaturePrivilegeConfig" + "section": "def-common.SubFeatureConfig", + "text": "SubFeatureConfig" }, - ">" + "[] | undefined" ], - "path": "x-pack/plugins/features/server/plugin.ts", + "path": "x-pack/plugins/features/common/kibana_feature.ts", "deprecated": false, - "trackAdoption": false, - "returnComment": [], - "children": [ - { - "parentPluginId": "features", - "id": "def-server.PluginSetupContract.subFeaturePrivilegeIterator.$1", - "type": "Object", - "tags": [], - "label": "feature", - "description": [], - "signature": [ - { - "pluginId": "features", - "scope": "common", - "docId": "kibFeaturesPluginApi", - "section": "def-common.KibanaFeature", - "text": "KibanaFeature" - } - ], - "path": "x-pack/plugins/features/server/feature_privilege_iterator/sub_feature_privilege_iterator.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "features", - "id": "def-server.PluginSetupContract.subFeaturePrivilegeIterator.$2", - "type": "Function", - "tags": [], - "label": "licenseHasAtLeast", - "description": [], - "signature": [ - "(licenseType: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\") => boolean | undefined" - ], - "path": "x-pack/plugins/features/server/feature_privilege_iterator/sub_feature_privilege_iterator.ts", - "deprecated": false, - "trackAdoption": false, - "returnComment": [], - "children": [ - { - "parentPluginId": "features", - "id": "def-server.PluginSetupContract.subFeaturePrivilegeIterator.$2.$1", - "type": "CompoundType", - "tags": [], - "label": "licenseType", - "description": [], - "signature": [ - "\"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\"" - ], - "path": "x-pack/plugins/features/server/feature_privilege_iterator/sub_feature_privilege_iterator.ts", - "deprecated": false, - "trackAdoption": false - } - ] - } - ] - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "features", - "id": "def-server.PluginStartContract", - "type": "Interface", - "tags": [], - "label": "PluginStartContract", - "description": [], - "path": "x-pack/plugins/features/server/plugin.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ + "trackAdoption": false + }, { "parentPluginId": "features", - "id": "def-server.PluginStartContract.getElasticsearchFeatures", - "type": "Function", + "id": "def-server.KibanaFeatureConfig.privilegesTooltip", + "type": "string", "tags": [], - "label": "getElasticsearchFeatures", + "label": "privilegesTooltip", + "description": [ + "\nOptional message to display on the Role Management screen when configuring permissions for this feature." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/features/common/kibana_feature.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "features", + "id": "def-server.KibanaFeatureConfig.reserved", + "type": "Object", + "tags": [ + "private" + ], + "label": "reserved", "description": [], "signature": [ - "() => ", - { - "pluginId": "features", - "scope": "common", - "docId": "kibFeaturesPluginApi", - "section": "def-common.ElasticsearchFeature", - "text": "ElasticsearchFeature" - }, - "[]" + "{ description: string; privileges: readonly ", + "ReservedKibanaPrivilege", + "[]; } | undefined" ], - "path": "x-pack/plugins/features/server/plugin.ts", + "path": "x-pack/plugins/features/common/kibana_feature.ts", "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] + "trackAdoption": false }, { "parentPluginId": "features", - "id": "def-server.PluginStartContract.getKibanaFeatures", - "type": "Function", + "id": "def-server.KibanaFeatureConfig.hidden", + "type": "CompoundType", "tags": [], - "label": "getKibanaFeatures", - "description": [], + "label": "hidden", + "description": [ + "\nIndicates whether the feature is available as a standalone feature. The feature can still be\nreferenced by other features, but it will not be displayed in any feature management UIs. By default, all features\nare visible." + ], "signature": [ - "() => ", - { - "pluginId": "features", - "scope": "common", - "docId": "kibFeaturesPluginApi", - "section": "def-common.KibanaFeature", - "text": "KibanaFeature" - }, - "[]" + "boolean | undefined" ], - "path": "x-pack/plugins/features/server/plugin.ts", + "path": "x-pack/plugins/features/common/kibana_feature.ts", "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/features.mdx b/api_docs/features.mdx index b7e4d8818348a..f945da877671e 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-07-17 +date: 2024-07-19 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 c29a79c8d0fde..71e1e90e312f6 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fieldFormats'] --- import fieldFormatsObj from './field_formats.devdocs.json'; diff --git a/api_docs/fields_metadata.devdocs.json b/api_docs/fields_metadata.devdocs.json index 63ccdbaad3943..f79e84746ba5b 100644 --- a/api_docs/fields_metadata.devdocs.json +++ b/api_docs/fields_metadata.devdocs.json @@ -160,7 +160,7 @@ "label": "ExtractedDatasetFields", "description": [], "signature": [ - "{ [x: string]: { name: string; } & { allowed_values?: ({ description: string; name: string; } & { expected_event_types?: string[] | undefined; beta?: string | undefined; })[] | undefined; beta?: string | undefined; dashed_name?: string | undefined; description?: string | undefined; doc_values?: boolean | undefined; example?: unknown; expected_values?: string[] | undefined; flat_name?: string | undefined; format?: string | undefined; ignore_above?: number | undefined; index?: boolean | undefined; input_format?: string | undefined; level?: string | undefined; multi_fields?: { flat_name: string; name: string; type: string; }[] | undefined; normalize?: string[] | undefined; object_type?: string | undefined; original_fieldset?: string | undefined; output_format?: string | undefined; output_precision?: number | undefined; pattern?: string | undefined; required?: boolean | undefined; scaling_factor?: number | undefined; short?: string | undefined; source?: \"unknown\" | \"ecs\" | \"integration\" | undefined; type?: string | undefined; }; }" + "{ [x: string]: { name: string; } & { allowed_values?: ({ description: string; name: string; } & { expected_event_types?: string[] | undefined; beta?: string | undefined; })[] | undefined; beta?: string | undefined; dashed_name?: string | undefined; description?: string | undefined; doc_values?: boolean | undefined; example?: unknown; expected_values?: string[] | undefined; flat_name?: string | undefined; format?: string | undefined; ignore_above?: number | undefined; index?: boolean | undefined; input_format?: string | undefined; level?: string | undefined; multi_fields?: { flat_name: string; name: string; type: string; }[] | undefined; normalize?: string[] | undefined; object_type?: string | undefined; original_fieldset?: string | undefined; output_format?: string | undefined; output_precision?: number | undefined; pattern?: string | undefined; required?: boolean | undefined; scaling_factor?: number | undefined; short?: string | undefined; source?: \"unknown\" | \"ecs\" | \"integration\" | \"metadata\" | undefined; type?: string | undefined; documentation_url?: string | undefined; }; }" ], "path": "x-pack/plugins/fields_metadata/server/services/fields_metadata/repositories/types.ts", "deprecated": false, @@ -336,7 +336,7 @@ "label": "pick", "description": [], "signature": [ - "(props: (\"source\" | \"type\" | \"normalize\" | \"short\" | \"format\" | \"name\" | \"index\" | \"pattern\" | \"description\" | \"doc_values\" | \"ignore_above\" | \"beta\" | \"required\" | \"level\" | \"allowed_values\" | \"dashed_name\" | \"example\" | \"expected_values\" | \"flat_name\" | \"input_format\" | \"multi_fields\" | \"object_type\" | \"original_fieldset\" | \"output_format\" | \"output_precision\" | \"scaling_factor\")[]) => { name?: string | undefined; } & { allowed_values?: ({ description: string; name: string; } & { expected_event_types?: string[] | undefined; beta?: string | undefined; })[] | undefined; beta?: string | undefined; dashed_name?: string | undefined; description?: string | undefined; doc_values?: boolean | undefined; example?: unknown; expected_values?: string[] | undefined; flat_name?: string | undefined; format?: string | undefined; ignore_above?: number | undefined; index?: boolean | undefined; input_format?: string | undefined; level?: string | undefined; multi_fields?: { flat_name: string; name: string; type: string; }[] | undefined; normalize?: string[] | undefined; object_type?: string | undefined; original_fieldset?: string | undefined; output_format?: string | undefined; output_precision?: number | undefined; pattern?: string | undefined; required?: boolean | undefined; scaling_factor?: number | undefined; short?: string | undefined; source?: \"unknown\" | \"ecs\" | \"integration\" | undefined; type?: string | undefined; }" + "(props: (\"source\" | \"type\" | \"normalize\" | \"short\" | \"format\" | \"name\" | \"index\" | \"pattern\" | \"description\" | \"doc_values\" | \"ignore_above\" | \"beta\" | \"required\" | \"level\" | \"allowed_values\" | \"dashed_name\" | \"example\" | \"expected_values\" | \"flat_name\" | \"input_format\" | \"multi_fields\" | \"object_type\" | \"original_fieldset\" | \"output_format\" | \"output_precision\" | \"scaling_factor\" | \"documentation_url\")[]) => { name?: string | undefined; } & { allowed_values?: ({ description: string; name: string; } & { expected_event_types?: string[] | undefined; beta?: string | undefined; })[] | undefined; beta?: string | undefined; dashed_name?: string | undefined; description?: string | undefined; doc_values?: boolean | undefined; example?: unknown; expected_values?: string[] | undefined; flat_name?: string | undefined; format?: string | undefined; ignore_above?: number | undefined; index?: boolean | undefined; input_format?: string | undefined; level?: string | undefined; multi_fields?: { flat_name: string; name: string; type: string; }[] | undefined; normalize?: string[] | undefined; object_type?: string | undefined; original_fieldset?: string | undefined; output_format?: string | undefined; output_precision?: number | undefined; pattern?: string | undefined; required?: boolean | undefined; scaling_factor?: number | undefined; short?: string | undefined; source?: \"unknown\" | \"ecs\" | \"integration\" | \"metadata\" | undefined; type?: string | undefined; documentation_url?: string | undefined; }" ], "path": "x-pack/plugins/fields_metadata/common/fields_metadata/models/field_metadata.ts", "deprecated": false, @@ -350,7 +350,7 @@ "label": "props", "description": [], "signature": [ - "(\"source\" | \"type\" | \"normalize\" | \"short\" | \"format\" | \"name\" | \"index\" | \"pattern\" | \"description\" | \"doc_values\" | \"ignore_above\" | \"beta\" | \"required\" | \"level\" | \"allowed_values\" | \"dashed_name\" | \"example\" | \"expected_values\" | \"flat_name\" | \"input_format\" | \"multi_fields\" | \"object_type\" | \"original_fieldset\" | \"output_format\" | \"output_precision\" | \"scaling_factor\")[]" + "(\"source\" | \"type\" | \"normalize\" | \"short\" | \"format\" | \"name\" | \"index\" | \"pattern\" | \"description\" | \"doc_values\" | \"ignore_above\" | \"beta\" | \"required\" | \"level\" | \"allowed_values\" | \"dashed_name\" | \"example\" | \"expected_values\" | \"flat_name\" | \"input_format\" | \"multi_fields\" | \"object_type\" | \"original_fieldset\" | \"output_format\" | \"output_precision\" | \"scaling_factor\" | \"documentation_url\")[]" ], "path": "x-pack/plugins/fields_metadata/common/fields_metadata/models/field_metadata.ts", "deprecated": false, @@ -368,7 +368,7 @@ "label": "toPlain", "description": [], "signature": [ - "() => { name: string; } & { allowed_values?: ({ description: string; name: string; } & { expected_event_types?: string[] | undefined; beta?: string | undefined; })[] | undefined; beta?: string | undefined; dashed_name?: string | undefined; description?: string | undefined; doc_values?: boolean | undefined; example?: unknown; expected_values?: string[] | undefined; flat_name?: string | undefined; format?: string | undefined; ignore_above?: number | undefined; index?: boolean | undefined; input_format?: string | undefined; level?: string | undefined; multi_fields?: { flat_name: string; name: string; type: string; }[] | undefined; normalize?: string[] | undefined; object_type?: string | undefined; original_fieldset?: string | undefined; output_format?: string | undefined; output_precision?: number | undefined; pattern?: string | undefined; required?: boolean | undefined; scaling_factor?: number | undefined; short?: string | undefined; source?: \"unknown\" | \"ecs\" | \"integration\" | undefined; type?: string | undefined; }" + "() => { name: string; } & { allowed_values?: ({ description: string; name: string; } & { expected_event_types?: string[] | undefined; beta?: string | undefined; })[] | undefined; beta?: string | undefined; dashed_name?: string | undefined; description?: string | undefined; doc_values?: boolean | undefined; example?: unknown; expected_values?: string[] | undefined; flat_name?: string | undefined; format?: string | undefined; ignore_above?: number | undefined; index?: boolean | undefined; input_format?: string | undefined; level?: string | undefined; multi_fields?: { flat_name: string; name: string; type: string; }[] | undefined; normalize?: string[] | undefined; object_type?: string | undefined; original_fieldset?: string | undefined; output_format?: string | undefined; output_precision?: number | undefined; pattern?: string | undefined; required?: boolean | undefined; scaling_factor?: number | undefined; short?: string | undefined; source?: \"unknown\" | \"ecs\" | \"integration\" | \"metadata\" | undefined; type?: string | undefined; documentation_url?: string | undefined; }" ], "path": "x-pack/plugins/fields_metadata/common/fields_metadata/models/field_metadata.ts", "deprecated": false, @@ -384,7 +384,7 @@ "label": "create", "description": [], "signature": [ - "(fieldMetadata: { name: string; } & { allowed_values?: ({ description: string; name: string; } & { expected_event_types?: string[] | undefined; beta?: string | undefined; })[] | undefined; beta?: string | undefined; dashed_name?: string | undefined; description?: string | undefined; doc_values?: boolean | undefined; example?: unknown; expected_values?: string[] | undefined; flat_name?: string | undefined; format?: string | undefined; ignore_above?: number | undefined; index?: boolean | undefined; input_format?: string | undefined; level?: string | undefined; multi_fields?: { flat_name: string; name: string; type: string; }[] | undefined; normalize?: string[] | undefined; object_type?: string | undefined; original_fieldset?: string | undefined; output_format?: string | undefined; output_precision?: number | undefined; pattern?: string | undefined; required?: boolean | undefined; scaling_factor?: number | undefined; short?: string | undefined; source?: \"unknown\" | \"ecs\" | \"integration\" | undefined; type?: string | undefined; }) => ", + "(fieldMetadata: { name: string; } & { allowed_values?: ({ description: string; name: string; } & { expected_event_types?: string[] | undefined; beta?: string | undefined; })[] | undefined; beta?: string | undefined; dashed_name?: string | undefined; description?: string | undefined; doc_values?: boolean | undefined; example?: unknown; expected_values?: string[] | undefined; flat_name?: string | undefined; format?: string | undefined; ignore_above?: number | undefined; index?: boolean | undefined; input_format?: string | undefined; level?: string | undefined; multi_fields?: { flat_name: string; name: string; type: string; }[] | undefined; normalize?: string[] | undefined; object_type?: string | undefined; original_fieldset?: string | undefined; output_format?: string | undefined; output_precision?: number | undefined; pattern?: string | undefined; required?: boolean | undefined; scaling_factor?: number | undefined; short?: string | undefined; source?: \"unknown\" | \"ecs\" | \"integration\" | \"metadata\" | undefined; type?: string | undefined; documentation_url?: string | undefined; }) => ", { "pluginId": "fieldsMetadata", "scope": "common", @@ -405,7 +405,7 @@ "label": "fieldMetadata", "description": [], "signature": [ - "{ name: string; } & { allowed_values?: ({ description: string; name: string; } & { expected_event_types?: string[] | undefined; beta?: string | undefined; })[] | undefined; beta?: string | undefined; dashed_name?: string | undefined; description?: string | undefined; doc_values?: boolean | undefined; example?: unknown; expected_values?: string[] | undefined; flat_name?: string | undefined; format?: string | undefined; ignore_above?: number | undefined; index?: boolean | undefined; input_format?: string | undefined; level?: string | undefined; multi_fields?: { flat_name: string; name: string; type: string; }[] | undefined; normalize?: string[] | undefined; object_type?: string | undefined; original_fieldset?: string | undefined; output_format?: string | undefined; output_precision?: number | undefined; pattern?: string | undefined; required?: boolean | undefined; scaling_factor?: number | undefined; short?: string | undefined; source?: \"unknown\" | \"ecs\" | \"integration\" | undefined; type?: string | undefined; }" + "{ name: string; } & { allowed_values?: ({ description: string; name: string; } & { expected_event_types?: string[] | undefined; beta?: string | undefined; })[] | undefined; beta?: string | undefined; dashed_name?: string | undefined; description?: string | undefined; doc_values?: boolean | undefined; example?: unknown; expected_values?: string[] | undefined; flat_name?: string | undefined; format?: string | undefined; ignore_above?: number | undefined; index?: boolean | undefined; input_format?: string | undefined; level?: string | undefined; multi_fields?: { flat_name: string; name: string; type: string; }[] | undefined; normalize?: string[] | undefined; object_type?: string | undefined; original_fieldset?: string | undefined; output_format?: string | undefined; output_precision?: number | undefined; pattern?: string | undefined; required?: boolean | undefined; scaling_factor?: number | undefined; short?: string | undefined; source?: \"unknown\" | \"ecs\" | \"integration\" | \"metadata\" | undefined; type?: string | undefined; documentation_url?: string | undefined; }" ], "path": "x-pack/plugins/fields_metadata/common/fields_metadata/models/field_metadata.ts", "deprecated": false, @@ -429,6 +429,23 @@ "deprecated": false, "trackAdoption": false, "children": [ + { + "parentPluginId": "fieldsMetadata", + "id": "def-common.FieldsMetadataDictionary.getFields", + "type": "Function", + "tags": [], + "label": "getFields", + "description": [], + "signature": [ + "() => ", + "FieldsMetadataMap" + ], + "path": "x-pack/plugins/fields_metadata/common/fields_metadata/models/fields_metadata_dictionary.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, { "parentPluginId": "fieldsMetadata", "id": "def-common.FieldsMetadataDictionary.pick", @@ -437,7 +454,7 @@ "label": "pick", "description": [], "signature": [ - "(attributes: (\"source\" | \"type\" | \"normalize\" | \"short\" | \"format\" | \"name\" | \"index\" | \"pattern\" | \"description\" | \"doc_values\" | \"ignore_above\" | \"beta\" | \"required\" | \"level\" | \"allowed_values\" | \"dashed_name\" | \"example\" | \"expected_values\" | \"flat_name\" | \"input_format\" | \"multi_fields\" | \"object_type\" | \"original_fieldset\" | \"output_format\" | \"output_precision\" | \"scaling_factor\")[]) => Record" + "(attributes: (\"source\" | \"type\" | \"normalize\" | \"short\" | \"format\" | \"name\" | \"index\" | \"pattern\" | \"description\" | \"doc_values\" | \"ignore_above\" | \"beta\" | \"required\" | \"level\" | \"allowed_values\" | \"dashed_name\" | \"example\" | \"expected_values\" | \"flat_name\" | \"input_format\" | \"multi_fields\" | \"object_type\" | \"original_fieldset\" | \"output_format\" | \"output_precision\" | \"scaling_factor\" | \"documentation_url\")[]) => Record" ], "path": "x-pack/plugins/fields_metadata/common/fields_metadata/models/fields_metadata_dictionary.ts", "deprecated": false, @@ -451,7 +468,7 @@ "label": "attributes", "description": [], "signature": [ - "(\"source\" | \"type\" | \"normalize\" | \"short\" | \"format\" | \"name\" | \"index\" | \"pattern\" | \"description\" | \"doc_values\" | \"ignore_above\" | \"beta\" | \"required\" | \"level\" | \"allowed_values\" | \"dashed_name\" | \"example\" | \"expected_values\" | \"flat_name\" | \"input_format\" | \"multi_fields\" | \"object_type\" | \"original_fieldset\" | \"output_format\" | \"output_precision\" | \"scaling_factor\")[]" + "(\"source\" | \"type\" | \"normalize\" | \"short\" | \"format\" | \"name\" | \"index\" | \"pattern\" | \"description\" | \"doc_values\" | \"ignore_above\" | \"beta\" | \"required\" | \"level\" | \"allowed_values\" | \"dashed_name\" | \"example\" | \"expected_values\" | \"flat_name\" | \"input_format\" | \"multi_fields\" | \"object_type\" | \"original_fieldset\" | \"output_format\" | \"output_precision\" | \"scaling_factor\" | \"documentation_url\")[]" ], "path": "x-pack/plugins/fields_metadata/common/fields_metadata/models/fields_metadata_dictionary.ts", "deprecated": false, @@ -469,7 +486,7 @@ "label": "toPlain", "description": [], "signature": [ - "() => Record" + "() => Record" ], "path": "x-pack/plugins/fields_metadata/common/fields_metadata/models/fields_metadata_dictionary.ts", "deprecated": false, @@ -539,7 +556,7 @@ "section": "def-common.FieldMetadata", "text": "FieldMetadata" }, - " extends { name: string; } & { allowed_values?: ({ description: string; name: string; } & { expected_event_types?: string[] | undefined; beta?: string | undefined; })[] | undefined; beta?: string | undefined; dashed_name?: string | undefined; description?: string | undefined; doc_values?: boolean | undefined; example?: unknown; expected_values?: string[] | undefined; flat_name?: string | undefined; format?: string | undefined; ignore_above?: number | undefined; index?: boolean | undefined; input_format?: string | undefined; level?: string | undefined; multi_fields?: { flat_name: string; name: string; type: string; }[] | undefined; normalize?: string[] | undefined; object_type?: string | undefined; original_fieldset?: string | undefined; output_format?: string | undefined; output_precision?: number | undefined; pattern?: string | undefined; required?: boolean | undefined; scaling_factor?: number | undefined; short?: string | undefined; source?: \"unknown\" | \"ecs\" | \"integration\" | undefined; type?: string | undefined; }" + " extends { name: string; } & { allowed_values?: ({ description: string; name: string; } & { expected_event_types?: string[] | undefined; beta?: string | undefined; })[] | undefined; beta?: string | undefined; dashed_name?: string | undefined; description?: string | undefined; doc_values?: boolean | undefined; example?: unknown; expected_values?: string[] | undefined; flat_name?: string | undefined; format?: string | undefined; ignore_above?: number | undefined; index?: boolean | undefined; input_format?: string | undefined; level?: string | undefined; multi_fields?: { flat_name: string; name: string; type: string; }[] | undefined; normalize?: string[] | undefined; object_type?: string | undefined; original_fieldset?: string | undefined; output_format?: string | undefined; output_precision?: number | undefined; pattern?: string | undefined; required?: boolean | undefined; scaling_factor?: number | undefined; short?: string | undefined; source?: \"unknown\" | \"ecs\" | \"integration\" | \"metadata\" | undefined; type?: string | undefined; documentation_url?: string | undefined; }" ], "path": "x-pack/plugins/fields_metadata/common/fields_metadata/models/field_metadata.ts", "deprecated": false, @@ -550,6 +567,21 @@ ], "enums": [], "misc": [ + { + "parentPluginId": "fieldsMetadata", + "id": "def-common.AnyFieldName", + "type": "Type", + "tags": [], + "label": "AnyFieldName", + "description": [], + "signature": [ + "string & {}" + ], + "path": "x-pack/plugins/fields_metadata/common/fields_metadata/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "fieldsMetadata", "id": "def-common.EcsFieldName", @@ -573,7 +605,7 @@ "label": "FieldAttribute", "description": [], "signature": [ - "\"source\" | \"type\" | \"normalize\" | \"short\" | \"format\" | \"name\" | \"index\" | \"pattern\" | \"description\" | \"doc_values\" | \"ignore_above\" | \"beta\" | \"required\" | \"level\" | \"allowed_values\" | \"dashed_name\" | \"example\" | \"expected_values\" | \"flat_name\" | \"input_format\" | \"multi_fields\" | \"object_type\" | \"original_fieldset\" | \"output_format\" | \"output_precision\" | \"scaling_factor\"" + "\"source\" | \"type\" | \"normalize\" | \"short\" | \"format\" | \"name\" | \"index\" | \"pattern\" | \"description\" | \"doc_values\" | \"ignore_above\" | \"beta\" | \"required\" | \"level\" | \"allowed_values\" | \"dashed_name\" | \"example\" | \"expected_values\" | \"flat_name\" | \"input_format\" | \"multi_fields\" | \"object_type\" | \"original_fieldset\" | \"output_format\" | \"output_precision\" | \"scaling_factor\" | \"documentation_url\"" ], "path": "x-pack/plugins/fields_metadata/common/fields_metadata/types.ts", "deprecated": false, @@ -588,7 +620,7 @@ "label": "FieldMetadataPlain", "description": [], "signature": [ - "{ name: string; } & { allowed_values?: ({ description: string; name: string; } & { expected_event_types?: string[] | undefined; beta?: string | undefined; })[] | undefined; beta?: string | undefined; dashed_name?: string | undefined; description?: string | undefined; doc_values?: boolean | undefined; example?: unknown; expected_values?: string[] | undefined; flat_name?: string | undefined; format?: string | undefined; ignore_above?: number | undefined; index?: boolean | undefined; input_format?: string | undefined; level?: string | undefined; multi_fields?: { flat_name: string; name: string; type: string; }[] | undefined; normalize?: string[] | undefined; object_type?: string | undefined; original_fieldset?: string | undefined; output_format?: string | undefined; output_precision?: number | undefined; pattern?: string | undefined; required?: boolean | undefined; scaling_factor?: number | undefined; short?: string | undefined; source?: \"unknown\" | \"ecs\" | \"integration\" | undefined; type?: string | undefined; }" + "{ name: string; } & { allowed_values?: ({ description: string; name: string; } & { expected_event_types?: string[] | undefined; beta?: string | undefined; })[] | undefined; beta?: string | undefined; dashed_name?: string | undefined; description?: string | undefined; doc_values?: boolean | undefined; example?: unknown; expected_values?: string[] | undefined; flat_name?: string | undefined; format?: string | undefined; ignore_above?: number | undefined; index?: boolean | undefined; input_format?: string | undefined; level?: string | undefined; multi_fields?: { flat_name: string; name: string; type: string; }[] | undefined; normalize?: string[] | undefined; object_type?: string | undefined; original_fieldset?: string | undefined; output_format?: string | undefined; output_precision?: number | undefined; pattern?: string | undefined; required?: boolean | undefined; scaling_factor?: number | undefined; short?: string | undefined; source?: \"unknown\" | \"ecs\" | \"integration\" | \"metadata\" | undefined; type?: string | undefined; documentation_url?: string | undefined; }" ], "path": "x-pack/plugins/fields_metadata/common/fields_metadata/types.ts", "deprecated": false, @@ -603,7 +635,15 @@ "label": "FieldName", "description": [], "signature": [ - "\"@timestamp\" | \"event.sequence\" | \"event.start\" | \"event.end\" | \"event.provider\" | \"event.duration\" | \"event.action\" | \"message\" | \"event.outcome\" | \"tags\" | \"event.kind\" | \"agent.name\" | \"container.id\" | \"host.name\" | \"labels\" | \"service.environment\" | \"service.name\" | \"ecs.version\" | \"agent.build.original\" | \"agent.ephemeral_id\" | \"agent.id\" | \"agent.type\" | \"agent.version\" | \"client.address\" | \"client.as.number\" | \"client.as.organization.name\" | \"client.bytes\" | \"client.domain\" | \"client.geo.city_name\" | \"client.geo.continent_code\" | \"client.geo.continent_name\" | \"client.geo.country_iso_code\" | \"client.geo.country_name\" | \"client.geo.location\" | \"client.geo.name\" | \"client.geo.postal_code\" | \"client.geo.region_iso_code\" | \"client.geo.region_name\" | \"client.geo.timezone\" | \"client.ip\" | \"client.mac\" | \"client.nat.ip\" | \"client.nat.port\" | \"client.packets\" | \"client.port\" | \"client.registered_domain\" | \"client.subdomain\" | \"client.top_level_domain\" | \"client.user.domain\" | \"client.user.email\" | \"client.user.full_name\" | \"client.user.group.domain\" | \"client.user.group.id\" | \"client.user.group.name\" | \"client.user.hash\" | \"client.user.id\" | \"client.user.name\" | \"client.user.roles\" | \"cloud.account.id\" | \"cloud.account.name\" | \"cloud.availability_zone\" | \"cloud.instance.id\" | \"cloud.instance.name\" | \"cloud.machine.type\" | \"cloud.origin.account.id\" | \"cloud.origin.account.name\" | \"cloud.origin.availability_zone\" | \"cloud.origin.instance.id\" | \"cloud.origin.instance.name\" | \"cloud.origin.machine.type\" | \"cloud.origin.project.id\" | \"cloud.origin.project.name\" | \"cloud.origin.provider\" | \"cloud.origin.region\" | \"cloud.origin.service.name\" | \"cloud.project.id\" | \"cloud.project.name\" | \"cloud.provider\" | \"cloud.region\" | \"cloud.service.name\" | \"cloud.target.account.id\" | \"cloud.target.account.name\" | \"cloud.target.availability_zone\" | \"cloud.target.instance.id\" | \"cloud.target.instance.name\" | \"cloud.target.machine.type\" | \"cloud.target.project.id\" | \"cloud.target.project.name\" | \"cloud.target.provider\" | \"cloud.target.region\" | \"cloud.target.service.name\" | \"container.cpu.usage\" | \"container.disk.read.bytes\" | \"container.disk.write.bytes\" | \"container.image.hash.all\" | \"container.image.name\" | \"container.image.tag\" | \"container.labels\" | \"container.memory.usage\" | \"container.name\" | \"container.network.egress.bytes\" | \"container.network.ingress.bytes\" | \"container.runtime\" | \"container.security_context.privileged\" | \"destination.address\" | \"destination.as.number\" | \"destination.as.organization.name\" | \"destination.bytes\" | \"destination.domain\" | \"destination.geo.city_name\" | \"destination.geo.continent_code\" | \"destination.geo.continent_name\" | \"destination.geo.country_iso_code\" | \"destination.geo.country_name\" | \"destination.geo.location\" | \"destination.geo.name\" | \"destination.geo.postal_code\" | \"destination.geo.region_iso_code\" | \"destination.geo.region_name\" | \"destination.geo.timezone\" | \"destination.ip\" | \"destination.mac\" | \"destination.nat.ip\" | \"destination.nat.port\" | \"destination.packets\" | \"destination.port\" | \"destination.registered_domain\" | \"destination.subdomain\" | \"destination.top_level_domain\" | \"destination.user.domain\" | \"destination.user.email\" | \"destination.user.full_name\" | \"destination.user.group.domain\" | \"destination.user.group.id\" | \"destination.user.group.name\" | \"destination.user.hash\" | \"destination.user.id\" | \"destination.user.name\" | \"destination.user.roles\" | \"device.id\" | \"device.manufacturer\" | \"device.model.identifier\" | \"device.model.name\" | \"dll.code_signature.digest_algorithm\" | \"dll.code_signature.exists\" | \"dll.code_signature.signing_id\" | \"dll.code_signature.status\" | \"dll.code_signature.subject_name\" | \"dll.code_signature.team_id\" | \"dll.code_signature.timestamp\" | \"dll.code_signature.trusted\" | \"dll.code_signature.valid\" | \"dll.hash.md5\" | \"dll.hash.sha1\" | \"dll.hash.sha256\" | \"dll.hash.sha384\" | \"dll.hash.sha512\" | \"dll.hash.ssdeep\" | \"dll.hash.tlsh\" | \"dll.name\" | \"dll.path\" | \"dll.pe.architecture\" | \"dll.pe.company\" | \"dll.pe.description\" | \"dll.pe.file_version\" | \"dll.pe.go_import_hash\" | \"dll.pe.go_imports\" | \"dll.pe.go_imports_names_entropy\" | \"dll.pe.go_imports_names_var_entropy\" | \"dll.pe.go_stripped\" | \"dll.pe.imphash\" | \"dll.pe.import_hash\" | \"dll.pe.imports\" | \"dll.pe.imports_names_entropy\" | \"dll.pe.imports_names_var_entropy\" | \"dll.pe.original_file_name\" | \"dll.pe.pehash\" | \"dll.pe.product\" | \"dll.pe.sections\" | \"dns.answers\" | \"dns.header_flags\" | \"dns.id\" | \"dns.op_code\" | \"dns.question.class\" | \"dns.question.name\" | \"dns.question.registered_domain\" | \"dns.question.subdomain\" | \"dns.question.top_level_domain\" | \"dns.question.type\" | \"dns.resolved_ip\" | \"dns.response_code\" | \"dns.type\" | \"email.attachments\" | \"file.extension\" | \"file.hash.md5\" | \"file.hash.sha1\" | \"file.hash.sha256\" | \"file.hash.sha384\" | \"file.hash.sha512\" | \"file.hash.ssdeep\" | \"file.hash.tlsh\" | \"file.mime_type\" | \"file.name\" | \"file.size\" | \"email.bcc.address\" | \"email.cc.address\" | \"email.content_type\" | \"email.delivery_timestamp\" | \"email.direction\" | \"email.from.address\" | \"email.local_id\" | \"email.message_id\" | \"email.origination_timestamp\" | \"email.reply_to.address\" | \"email.sender.address\" | \"email.subject\" | \"email.to.address\" | \"email.x_mailer\" | \"error.code\" | \"error.id\" | \"error.message\" | \"error.stack_trace\" | \"error.type\" | \"event.agent_id_status\" | \"event.category\" | \"event.code\" | \"event.created\" | \"event.dataset\" | \"event.hash\" | \"event.id\" | \"event.ingested\" | \"event.module\" | \"event.original\" | \"event.reason\" | \"event.reference\" | \"event.risk_score\" | \"event.risk_score_norm\" | \"event.severity\" | \"event.timezone\" | \"event.type\" | \"event.url\" | \"faas.coldstart\" | \"faas.execution\" | \"faas.id\" | \"faas.name\" | \"faas.version\" | \"file.accessed\" | \"file.attributes\" | \"file.code_signature.digest_algorithm\" | \"file.code_signature.exists\" | \"file.code_signature.signing_id\" | \"file.code_signature.status\" | \"file.code_signature.subject_name\" | \"file.code_signature.team_id\" | \"file.code_signature.timestamp\" | \"file.code_signature.trusted\" | \"file.code_signature.valid\" | \"file.created\" | \"file.ctime\" | \"file.device\" | \"file.directory\" | \"file.drive_letter\" | \"file.elf.architecture\" | \"file.elf.byte_order\" | \"file.elf.cpu_type\" | \"file.elf.creation_date\" | \"file.elf.exports\" | \"file.elf.go_import_hash\" | \"file.elf.go_imports\" | \"file.elf.go_imports_names_entropy\" | \"file.elf.go_imports_names_var_entropy\" | \"file.elf.go_stripped\" | \"file.elf.header.abi_version\" | \"file.elf.header.class\" | \"file.elf.header.data\" | \"file.elf.header.entrypoint\" | \"file.elf.header.object_version\" | \"file.elf.header.os_abi\" | \"file.elf.header.type\" | \"file.elf.header.version\" | \"file.elf.import_hash\" | \"file.elf.imports\" | \"file.elf.imports_names_entropy\" | \"file.elf.imports_names_var_entropy\" | \"file.elf.sections\" | \"file.elf.segments\" | \"file.elf.shared_libraries\" | \"file.elf.telfhash\" | \"file.fork_name\" | \"file.gid\" | \"file.group\" | \"file.inode\" | \"file.macho.go_import_hash\" | \"file.macho.go_imports\" | \"file.macho.go_imports_names_entropy\" | \"file.macho.go_imports_names_var_entropy\" | \"file.macho.go_stripped\" | \"file.macho.import_hash\" | \"file.macho.imports\" | \"file.macho.imports_names_entropy\" | \"file.macho.imports_names_var_entropy\" | \"file.macho.sections\" | \"file.macho.symhash\" | \"file.mode\" | \"file.mtime\" | \"file.owner\" | \"file.path\" | \"file.pe.architecture\" | \"file.pe.company\" | \"file.pe.description\" | \"file.pe.file_version\" | \"file.pe.go_import_hash\" | \"file.pe.go_imports\" | \"file.pe.go_imports_names_entropy\" | \"file.pe.go_imports_names_var_entropy\" | \"file.pe.go_stripped\" | \"file.pe.imphash\" | \"file.pe.import_hash\" | \"file.pe.imports\" | \"file.pe.imports_names_entropy\" | \"file.pe.imports_names_var_entropy\" | \"file.pe.original_file_name\" | \"file.pe.pehash\" | \"file.pe.product\" | \"file.pe.sections\" | \"file.target_path\" | \"file.type\" | \"file.uid\" | \"file.x509.alternative_names\" | \"file.x509.issuer.common_name\" | \"file.x509.issuer.country\" | \"file.x509.issuer.distinguished_name\" | \"file.x509.issuer.locality\" | \"file.x509.issuer.organization\" | \"file.x509.issuer.organizational_unit\" | \"file.x509.issuer.state_or_province\" | \"file.x509.not_after\" | \"file.x509.not_before\" | \"file.x509.public_key_algorithm\" | \"file.x509.public_key_curve\" | \"file.x509.public_key_exponent\" | \"file.x509.public_key_size\" | \"file.x509.serial_number\" | \"file.x509.signature_algorithm\" | \"file.x509.subject.common_name\" | \"file.x509.subject.country\" | \"file.x509.subject.distinguished_name\" | \"file.x509.subject.locality\" | \"file.x509.subject.organization\" | \"file.x509.subject.organizational_unit\" | \"file.x509.subject.state_or_province\" | \"file.x509.version_number\" | \"group.domain\" | \"group.id\" | \"group.name\" | \"host.architecture\" | \"host.boot.id\" | \"host.cpu.usage\" | \"host.disk.read.bytes\" | \"host.disk.write.bytes\" | \"host.domain\" | \"host.geo.city_name\" | \"host.geo.continent_code\" | \"host.geo.continent_name\" | \"host.geo.country_iso_code\" | \"host.geo.country_name\" | \"host.geo.location\" | \"host.geo.name\" | \"host.geo.postal_code\" | \"host.geo.region_iso_code\" | \"host.geo.region_name\" | \"host.geo.timezone\" | \"host.hostname\" | \"host.id\" | \"host.ip\" | \"host.mac\" | \"host.network.egress.bytes\" | \"host.network.egress.packets\" | \"host.network.ingress.bytes\" | \"host.network.ingress.packets\" | \"host.os.family\" | \"host.os.full\" | \"host.os.kernel\" | \"host.os.name\" | \"host.os.platform\" | \"host.os.type\" | \"host.os.version\" | \"host.pid_ns_ino\" | \"host.risk.calculated_level\" | \"host.risk.calculated_score\" | \"host.risk.calculated_score_norm\" | \"host.risk.static_level\" | \"host.risk.static_score\" | \"host.risk.static_score_norm\" | \"host.type\" | \"host.uptime\" | \"http.request.body.bytes\" | \"http.request.body.content\" | \"http.request.bytes\" | \"http.request.id\" | \"http.request.method\" | \"http.request.mime_type\" | \"http.request.referrer\" | \"http.response.body.bytes\" | \"http.response.body.content\" | \"http.response.bytes\" | \"http.response.mime_type\" | \"http.response.status_code\" | \"http.version\" | \"log.file.path\" | \"log.level\" | \"log.logger\" | \"log.origin.file.line\" | \"log.origin.file.name\" | \"log.origin.function\" | \"log.syslog\" | \"network.application\" | \"network.bytes\" | \"network.community_id\" | \"network.direction\" | \"network.forwarded_ip\" | \"network.iana_number\" | \"network.inner\" | \"network.name\" | \"network.packets\" | \"network.protocol\" | \"network.transport\" | \"network.type\" | \"network.vlan.id\" | \"network.vlan.name\" | \"observer.egress\" | \"observer.geo.city_name\" | \"observer.geo.continent_code\" | \"observer.geo.continent_name\" | \"observer.geo.country_iso_code\" | \"observer.geo.country_name\" | \"observer.geo.location\" | \"observer.geo.name\" | \"observer.geo.postal_code\" | \"observer.geo.region_iso_code\" | \"observer.geo.region_name\" | \"observer.geo.timezone\" | \"observer.hostname\" | \"observer.ingress\" | \"observer.ip\" | \"observer.mac\" | \"observer.name\" | \"observer.os.family\" | \"observer.os.full\" | \"observer.os.kernel\" | \"observer.os.name\" | \"observer.os.platform\" | \"observer.os.type\" | \"observer.os.version\" | \"observer.product\" | \"observer.serial_number\" | \"observer.type\" | \"observer.vendor\" | \"observer.version\" | \"orchestrator.api_version\" | \"orchestrator.cluster.id\" | \"orchestrator.cluster.name\" | \"orchestrator.cluster.url\" | \"orchestrator.cluster.version\" | \"orchestrator.namespace\" | \"orchestrator.organization\" | \"orchestrator.resource.annotation\" | \"orchestrator.resource.id\" | \"orchestrator.resource.ip\" | \"orchestrator.resource.label\" | \"orchestrator.resource.name\" | \"orchestrator.resource.parent.type\" | \"orchestrator.resource.type\" | \"orchestrator.type\" | \"organization.id\" | \"organization.name\" | \"package.architecture\" | \"package.build_version\" | \"package.checksum\" | \"package.description\" | \"package.install_scope\" | \"package.installed\" | \"package.license\" | \"package.name\" | \"package.path\" | \"package.reference\" | \"package.size\" | \"package.type\" | \"package.version\" | \"process.args\" | \"process.args_count\" | \"process.code_signature.digest_algorithm\" | \"process.code_signature.exists\" | \"process.code_signature.signing_id\" | \"process.code_signature.status\" | \"process.code_signature.subject_name\" | \"process.code_signature.team_id\" | \"process.code_signature.timestamp\" | \"process.code_signature.trusted\" | \"process.code_signature.valid\" | \"process.command_line\" | \"process.elf.architecture\" | \"process.elf.byte_order\" | \"process.elf.cpu_type\" | \"process.elf.creation_date\" | \"process.elf.exports\" | \"process.elf.go_import_hash\" | \"process.elf.go_imports\" | \"process.elf.go_imports_names_entropy\" | \"process.elf.go_imports_names_var_entropy\" | \"process.elf.go_stripped\" | \"process.elf.header.abi_version\" | \"process.elf.header.class\" | \"process.elf.header.data\" | \"process.elf.header.entrypoint\" | \"process.elf.header.object_version\" | \"process.elf.header.os_abi\" | \"process.elf.header.type\" | \"process.elf.header.version\" | \"process.elf.import_hash\" | \"process.elf.imports\" | \"process.elf.imports_names_entropy\" | \"process.elf.imports_names_var_entropy\" | \"process.elf.sections\" | \"process.elf.segments\" | \"process.elf.shared_libraries\" | \"process.elf.telfhash\" | \"process.end\" | \"process.entity_id\" | \"process.entry_leader.args\" | \"process.entry_leader.args_count\" | \"process.entry_leader.attested_groups.name\" | \"process.entry_leader.attested_user.id\" | \"process.entry_leader.attested_user.name\" | \"process.entry_leader.command_line\" | \"process.entry_leader.entity_id\" | \"process.entry_leader.entry_meta.source.ip\" | \"process.entry_leader.entry_meta.type\" | \"process.entry_leader.executable\" | \"process.entry_leader.group.id\" | \"process.entry_leader.group.name\" | \"process.entry_leader.interactive\" | \"process.entry_leader.name\" | \"process.entry_leader.parent.entity_id\" | \"process.entry_leader.parent.pid\" | \"process.entry_leader.parent.session_leader.entity_id\" | \"process.entry_leader.parent.session_leader.pid\" | \"process.entry_leader.parent.session_leader.start\" | \"process.entry_leader.parent.session_leader.vpid\" | \"process.entry_leader.parent.start\" | \"process.entry_leader.parent.vpid\" | \"process.entry_leader.pid\" | \"process.entry_leader.real_group.id\" | \"process.entry_leader.real_group.name\" | \"process.entry_leader.real_user.id\" | \"process.entry_leader.real_user.name\" | \"process.entry_leader.same_as_process\" | \"process.entry_leader.saved_group.id\" | \"process.entry_leader.saved_group.name\" | \"process.entry_leader.saved_user.id\" | \"process.entry_leader.saved_user.name\" | \"process.entry_leader.start\" | \"process.entry_leader.supplemental_groups.id\" | \"process.entry_leader.supplemental_groups.name\" | \"process.entry_leader.tty\" | \"process.entry_leader.user.id\" | \"process.entry_leader.user.name\" | \"process.entry_leader.vpid\" | \"process.entry_leader.working_directory\" | \"process.env_vars\" | \"process.executable\" | \"process.exit_code\" | \"process.group_leader.args\" | \"process.group_leader.args_count\" | \"process.group_leader.command_line\" | \"process.group_leader.entity_id\" | \"process.group_leader.executable\" | \"process.group_leader.group.id\" | \"process.group_leader.group.name\" | \"process.group_leader.interactive\" | \"process.group_leader.name\" | \"process.group_leader.pid\" | \"process.group_leader.real_group.id\" | \"process.group_leader.real_group.name\" | \"process.group_leader.real_user.id\" | \"process.group_leader.real_user.name\" | \"process.group_leader.same_as_process\" | \"process.group_leader.saved_group.id\" | \"process.group_leader.saved_group.name\" | \"process.group_leader.saved_user.id\" | \"process.group_leader.saved_user.name\" | \"process.group_leader.start\" | \"process.group_leader.supplemental_groups.id\" | \"process.group_leader.supplemental_groups.name\" | \"process.group_leader.tty\" | \"process.group_leader.user.id\" | \"process.group_leader.user.name\" | \"process.group_leader.vpid\" | \"process.group_leader.working_directory\" | \"process.hash.md5\" | \"process.hash.sha1\" | \"process.hash.sha256\" | \"process.hash.sha384\" | \"process.hash.sha512\" | \"process.hash.ssdeep\" | \"process.hash.tlsh\" | \"process.interactive\" | \"process.io\" | \"process.macho.go_import_hash\" | \"process.macho.go_imports\" | \"process.macho.go_imports_names_entropy\" | \"process.macho.go_imports_names_var_entropy\" | \"process.macho.go_stripped\" | \"process.macho.import_hash\" | \"process.macho.imports\" | \"process.macho.imports_names_entropy\" | \"process.macho.imports_names_var_entropy\" | \"process.macho.sections\" | \"process.macho.symhash\" | \"process.name\" | \"process.parent.args\" | \"process.parent.args_count\" | \"process.parent.code_signature.digest_algorithm\" | \"process.parent.code_signature.exists\" | \"process.parent.code_signature.signing_id\" | \"process.parent.code_signature.status\" | \"process.parent.code_signature.subject_name\" | \"process.parent.code_signature.team_id\" | \"process.parent.code_signature.timestamp\" | \"process.parent.code_signature.trusted\" | \"process.parent.code_signature.valid\" | \"process.parent.command_line\" | \"process.parent.elf.architecture\" | \"process.parent.elf.byte_order\" | \"process.parent.elf.cpu_type\" | \"process.parent.elf.creation_date\" | \"process.parent.elf.exports\" | \"process.parent.elf.go_import_hash\" | \"process.parent.elf.go_imports\" | \"process.parent.elf.go_imports_names_entropy\" | \"process.parent.elf.go_imports_names_var_entropy\" | \"process.parent.elf.go_stripped\" | \"process.parent.elf.header.abi_version\" | \"process.parent.elf.header.class\" | \"process.parent.elf.header.data\" | \"process.parent.elf.header.entrypoint\" | \"process.parent.elf.header.object_version\" | \"process.parent.elf.header.os_abi\" | \"process.parent.elf.header.type\" | \"process.parent.elf.header.version\" | \"process.parent.elf.import_hash\" | \"process.parent.elf.imports\" | \"process.parent.elf.imports_names_entropy\" | \"process.parent.elf.imports_names_var_entropy\" | \"process.parent.elf.sections\" | \"process.parent.elf.segments\" | \"process.parent.elf.shared_libraries\" | \"process.parent.elf.telfhash\" | \"process.parent.end\" | \"process.parent.entity_id\" | \"process.parent.executable\" | \"process.parent.exit_code\" | \"process.parent.group.id\" | \"process.parent.group.name\" | \"process.parent.group_leader.entity_id\" | \"process.parent.group_leader.pid\" | \"process.parent.group_leader.start\" | \"process.parent.group_leader.vpid\" | \"process.parent.hash.md5\" | \"process.parent.hash.sha1\" | \"process.parent.hash.sha256\" | \"process.parent.hash.sha384\" | \"process.parent.hash.sha512\" | \"process.parent.hash.ssdeep\" | \"process.parent.hash.tlsh\" | \"process.parent.interactive\" | \"process.parent.macho.go_import_hash\" | \"process.parent.macho.go_imports\" | \"process.parent.macho.go_imports_names_entropy\" | \"process.parent.macho.go_imports_names_var_entropy\" | \"process.parent.macho.go_stripped\" | \"process.parent.macho.import_hash\" | \"process.parent.macho.imports\" | \"process.parent.macho.imports_names_entropy\" | \"process.parent.macho.imports_names_var_entropy\" | \"process.parent.macho.sections\" | \"process.parent.macho.symhash\" | \"process.parent.name\" | \"process.parent.pe.architecture\" | \"process.parent.pe.company\" | \"process.parent.pe.description\" | \"process.parent.pe.file_version\" | \"process.parent.pe.go_import_hash\" | \"process.parent.pe.go_imports\" | \"process.parent.pe.go_imports_names_entropy\" | \"process.parent.pe.go_imports_names_var_entropy\" | \"process.parent.pe.go_stripped\" | \"process.parent.pe.imphash\" | \"process.parent.pe.import_hash\" | \"process.parent.pe.imports\" | \"process.parent.pe.imports_names_entropy\" | \"process.parent.pe.imports_names_var_entropy\" | \"process.parent.pe.original_file_name\" | \"process.parent.pe.pehash\" | \"process.parent.pe.product\" | \"process.parent.pe.sections\" | \"process.parent.pgid\" | \"process.parent.pid\" | \"process.parent.real_group.id\" | \"process.parent.real_group.name\" | \"process.parent.real_user.id\" | \"process.parent.real_user.name\" | \"process.parent.saved_group.id\" | \"process.parent.saved_group.name\" | \"process.parent.saved_user.id\" | \"process.parent.saved_user.name\" | \"process.parent.start\" | \"process.parent.supplemental_groups.id\" | \"process.parent.supplemental_groups.name\" | \"process.parent.thread.capabilities.effective\" | \"process.parent.thread.capabilities.permitted\" | \"process.parent.thread.id\" | \"process.parent.thread.name\" | \"process.parent.title\" | \"process.parent.tty\" | \"process.parent.uptime\" | \"process.parent.user.id\" | \"process.parent.user.name\" | \"process.parent.vpid\" | \"process.parent.working_directory\" | \"process.pe.architecture\" | \"process.pe.company\" | \"process.pe.description\" | \"process.pe.file_version\" | \"process.pe.go_import_hash\" | \"process.pe.go_imports\" | \"process.pe.go_imports_names_entropy\" | \"process.pe.go_imports_names_var_entropy\" | \"process.pe.go_stripped\" | \"process.pe.imphash\" | \"process.pe.import_hash\" | \"process.pe.imports\" | \"process.pe.imports_names_entropy\" | \"process.pe.imports_names_var_entropy\" | \"process.pe.original_file_name\" | \"process.pe.pehash\" | \"process.pe.product\" | \"process.pe.sections\" | \"process.pgid\" | \"process.pid\" | \"process.previous.args\" | \"process.previous.args_count\" | \"process.previous.executable\" | \"process.real_group.id\" | \"process.real_group.name\" | \"process.real_user.id\" | \"process.real_user.name\" | \"process.saved_group.id\" | \"process.saved_group.name\" | \"process.saved_user.id\" | \"process.saved_user.name\" | \"process.session_leader.args\" | \"process.session_leader.args_count\" | \"process.session_leader.command_line\" | \"process.session_leader.entity_id\" | \"process.session_leader.executable\" | \"process.session_leader.group.id\" | \"process.session_leader.group.name\" | \"process.session_leader.interactive\" | \"process.session_leader.name\" | \"process.session_leader.parent.entity_id\" | \"process.session_leader.parent.pid\" | \"process.session_leader.parent.session_leader.entity_id\" | \"process.session_leader.parent.session_leader.pid\" | \"process.session_leader.parent.session_leader.start\" | \"process.session_leader.parent.session_leader.vpid\" | \"process.session_leader.parent.start\" | \"process.session_leader.parent.vpid\" | \"process.session_leader.pid\" | \"process.session_leader.real_group.id\" | \"process.session_leader.real_group.name\" | \"process.session_leader.real_user.id\" | \"process.session_leader.real_user.name\" | \"process.session_leader.same_as_process\" | \"process.session_leader.saved_group.id\" | \"process.session_leader.saved_group.name\" | \"process.session_leader.saved_user.id\" | \"process.session_leader.saved_user.name\" | \"process.session_leader.start\" | \"process.session_leader.supplemental_groups.id\" | \"process.session_leader.supplemental_groups.name\" | \"process.session_leader.tty\" | \"process.session_leader.user.id\" | \"process.session_leader.user.name\" | \"process.session_leader.vpid\" | \"process.session_leader.working_directory\" | \"process.start\" | \"process.supplemental_groups.id\" | \"process.supplemental_groups.name\" | \"process.thread.capabilities.effective\" | \"process.thread.capabilities.permitted\" | \"process.thread.id\" | \"process.thread.name\" | \"process.title\" | \"process.tty\" | \"process.uptime\" | \"process.user.id\" | \"process.user.name\" | \"process.vpid\" | \"process.working_directory\" | \"registry.data.bytes\" | \"registry.data.strings\" | \"registry.data.type\" | \"registry.hive\" | \"registry.key\" | \"registry.path\" | \"registry.value\" | \"related.hash\" | \"related.hosts\" | \"related.ip\" | \"related.user\" | \"rule.author\" | \"rule.category\" | \"rule.description\" | \"rule.id\" | \"rule.license\" | \"rule.name\" | \"rule.reference\" | \"rule.ruleset\" | \"rule.uuid\" | \"rule.version\" | \"server.address\" | \"server.as.number\" | \"server.as.organization.name\" | \"server.bytes\" | \"server.domain\" | \"server.geo.city_name\" | \"server.geo.continent_code\" | \"server.geo.continent_name\" | \"server.geo.country_iso_code\" | \"server.geo.country_name\" | \"server.geo.location\" | \"server.geo.name\" | \"server.geo.postal_code\" | \"server.geo.region_iso_code\" | \"server.geo.region_name\" | \"server.geo.timezone\" | \"server.ip\" | \"server.mac\" | \"server.nat.ip\" | \"server.nat.port\" | \"server.packets\" | \"server.port\" | \"server.registered_domain\" | \"server.subdomain\" | \"server.top_level_domain\" | \"server.user.domain\" | \"server.user.email\" | \"server.user.full_name\" | \"server.user.group.domain\" | \"server.user.group.id\" | \"server.user.group.name\" | \"server.user.hash\" | \"server.user.id\" | \"server.user.name\" | \"server.user.roles\" | \"service.address\" | \"service.ephemeral_id\" | \"service.id\" | \"service.node.name\" | \"service.node.role\" | \"service.node.roles\" | \"service.origin.address\" | \"service.origin.environment\" | \"service.origin.ephemeral_id\" | \"service.origin.id\" | \"service.origin.name\" | \"service.origin.node.name\" | \"service.origin.node.role\" | \"service.origin.node.roles\" | \"service.origin.state\" | \"service.origin.type\" | \"service.origin.version\" | \"service.state\" | \"service.target.address\" | \"service.target.environment\" | \"service.target.ephemeral_id\" | \"service.target.id\" | \"service.target.name\" | \"service.target.node.name\" | \"service.target.node.role\" | \"service.target.node.roles\" | \"service.target.state\" | \"service.target.type\" | \"service.target.version\" | \"service.type\" | \"service.version\" | \"source.address\" | \"source.as.number\" | \"source.as.organization.name\" | \"source.bytes\" | \"source.domain\" | \"source.geo.city_name\" | \"source.geo.continent_code\" | \"source.geo.continent_name\" | \"source.geo.country_iso_code\" | \"source.geo.country_name\" | \"source.geo.location\" | \"source.geo.name\" | \"source.geo.postal_code\" | \"source.geo.region_iso_code\" | \"source.geo.region_name\" | \"source.geo.timezone\" | \"source.ip\" | \"source.mac\" | \"source.nat.ip\" | \"source.nat.port\" | \"source.packets\" | \"source.port\" | \"source.registered_domain\" | \"source.subdomain\" | \"source.top_level_domain\" | \"source.user.domain\" | \"source.user.email\" | \"source.user.full_name\" | \"source.user.group.domain\" | \"source.user.group.id\" | \"source.user.group.name\" | \"source.user.hash\" | \"source.user.id\" | \"source.user.name\" | \"source.user.roles\" | \"span.id\" | \"threat.enrichments\" | \"threat.feed.dashboard_id\" | \"threat.feed.description\" | \"threat.feed.name\" | \"threat.feed.reference\" | \"threat.framework\" | \"threat.group.alias\" | \"threat.group.id\" | \"threat.group.name\" | \"threat.group.reference\" | \"threat.indicator.as.number\" | \"threat.indicator.as.organization.name\" | \"threat.indicator.confidence\" | \"threat.indicator.description\" | \"threat.indicator.email.address\" | \"threat.indicator.file.accessed\" | \"threat.indicator.file.attributes\" | \"threat.indicator.file.code_signature.digest_algorithm\" | \"threat.indicator.file.code_signature.exists\" | \"threat.indicator.file.code_signature.signing_id\" | \"threat.indicator.file.code_signature.status\" | \"threat.indicator.file.code_signature.subject_name\" | \"threat.indicator.file.code_signature.team_id\" | \"threat.indicator.file.code_signature.timestamp\" | \"threat.indicator.file.code_signature.trusted\" | \"threat.indicator.file.code_signature.valid\" | \"threat.indicator.file.created\" | \"threat.indicator.file.ctime\" | \"threat.indicator.file.device\" | \"threat.indicator.file.directory\" | \"threat.indicator.file.drive_letter\" | \"threat.indicator.file.elf.architecture\" | \"threat.indicator.file.elf.byte_order\" | \"threat.indicator.file.elf.cpu_type\" | \"threat.indicator.file.elf.creation_date\" | \"threat.indicator.file.elf.exports\" | \"threat.indicator.file.elf.go_import_hash\" | \"threat.indicator.file.elf.go_imports\" | \"threat.indicator.file.elf.go_imports_names_entropy\" | \"threat.indicator.file.elf.go_imports_names_var_entropy\" | \"threat.indicator.file.elf.go_stripped\" | \"threat.indicator.file.elf.header.abi_version\" | \"threat.indicator.file.elf.header.class\" | \"threat.indicator.file.elf.header.data\" | \"threat.indicator.file.elf.header.entrypoint\" | \"threat.indicator.file.elf.header.object_version\" | \"threat.indicator.file.elf.header.os_abi\" | \"threat.indicator.file.elf.header.type\" | \"threat.indicator.file.elf.header.version\" | \"threat.indicator.file.elf.import_hash\" | \"threat.indicator.file.elf.imports\" | \"threat.indicator.file.elf.imports_names_entropy\" | \"threat.indicator.file.elf.imports_names_var_entropy\" | \"threat.indicator.file.elf.sections\" | \"threat.indicator.file.elf.segments\" | \"threat.indicator.file.elf.shared_libraries\" | \"threat.indicator.file.elf.telfhash\" | \"threat.indicator.file.extension\" | \"threat.indicator.file.fork_name\" | \"threat.indicator.file.gid\" | \"threat.indicator.file.group\" | \"threat.indicator.file.hash.md5\" | \"threat.indicator.file.hash.sha1\" | \"threat.indicator.file.hash.sha256\" | \"threat.indicator.file.hash.sha384\" | \"threat.indicator.file.hash.sha512\" | \"threat.indicator.file.hash.ssdeep\" | \"threat.indicator.file.hash.tlsh\" | \"threat.indicator.file.inode\" | \"threat.indicator.file.mime_type\" | \"threat.indicator.file.mode\" | \"threat.indicator.file.mtime\" | \"threat.indicator.file.name\" | \"threat.indicator.file.owner\" | \"threat.indicator.file.path\" | \"threat.indicator.file.pe.architecture\" | \"threat.indicator.file.pe.company\" | \"threat.indicator.file.pe.description\" | \"threat.indicator.file.pe.file_version\" | \"threat.indicator.file.pe.go_import_hash\" | \"threat.indicator.file.pe.go_imports\" | \"threat.indicator.file.pe.go_imports_names_entropy\" | \"threat.indicator.file.pe.go_imports_names_var_entropy\" | \"threat.indicator.file.pe.go_stripped\" | \"threat.indicator.file.pe.imphash\" | \"threat.indicator.file.pe.import_hash\" | \"threat.indicator.file.pe.imports\" | \"threat.indicator.file.pe.imports_names_entropy\" | \"threat.indicator.file.pe.imports_names_var_entropy\" | \"threat.indicator.file.pe.original_file_name\" | \"threat.indicator.file.pe.pehash\" | \"threat.indicator.file.pe.product\" | \"threat.indicator.file.pe.sections\" | \"threat.indicator.file.size\" | \"threat.indicator.file.target_path\" | \"threat.indicator.file.type\" | \"threat.indicator.file.uid\" | \"threat.indicator.file.x509.alternative_names\" | \"threat.indicator.file.x509.issuer.common_name\" | \"threat.indicator.file.x509.issuer.country\" | \"threat.indicator.file.x509.issuer.distinguished_name\" | \"threat.indicator.file.x509.issuer.locality\" | \"threat.indicator.file.x509.issuer.organization\" | \"threat.indicator.file.x509.issuer.organizational_unit\" | \"threat.indicator.file.x509.issuer.state_or_province\" | \"threat.indicator.file.x509.not_after\" | \"threat.indicator.file.x509.not_before\" | \"threat.indicator.file.x509.public_key_algorithm\" | \"threat.indicator.file.x509.public_key_curve\" | \"threat.indicator.file.x509.public_key_exponent\" | \"threat.indicator.file.x509.public_key_size\" | \"threat.indicator.file.x509.serial_number\" | \"threat.indicator.file.x509.signature_algorithm\" | \"threat.indicator.file.x509.subject.common_name\" | \"threat.indicator.file.x509.subject.country\" | \"threat.indicator.file.x509.subject.distinguished_name\" | \"threat.indicator.file.x509.subject.locality\" | \"threat.indicator.file.x509.subject.organization\" | \"threat.indicator.file.x509.subject.organizational_unit\" | \"threat.indicator.file.x509.subject.state_or_province\" | \"threat.indicator.file.x509.version_number\" | \"threat.indicator.first_seen\" | \"threat.indicator.geo.city_name\" | \"threat.indicator.geo.continent_code\" | \"threat.indicator.geo.continent_name\" | \"threat.indicator.geo.country_iso_code\" | \"threat.indicator.geo.country_name\" | \"threat.indicator.geo.location\" | \"threat.indicator.geo.name\" | \"threat.indicator.geo.postal_code\" | \"threat.indicator.geo.region_iso_code\" | \"threat.indicator.geo.region_name\" | \"threat.indicator.geo.timezone\" | \"threat.indicator.ip\" | \"threat.indicator.last_seen\" | \"threat.indicator.marking.tlp\" | \"threat.indicator.marking.tlp_version\" | \"threat.indicator.modified_at\" | \"threat.indicator.name\" | \"threat.indicator.port\" | \"threat.indicator.provider\" | \"threat.indicator.reference\" | \"threat.indicator.registry.data.bytes\" | \"threat.indicator.registry.data.strings\" | \"threat.indicator.registry.data.type\" | \"threat.indicator.registry.hive\" | \"threat.indicator.registry.key\" | \"threat.indicator.registry.path\" | \"threat.indicator.registry.value\" | \"threat.indicator.scanner_stats\" | \"threat.indicator.sightings\" | \"threat.indicator.type\" | \"threat.indicator.url.domain\" | \"threat.indicator.url.extension\" | \"threat.indicator.url.fragment\" | \"threat.indicator.url.full\" | \"threat.indicator.url.original\" | \"threat.indicator.url.password\" | \"threat.indicator.url.path\" | \"threat.indicator.url.port\" | \"threat.indicator.url.query\" | \"threat.indicator.url.registered_domain\" | \"threat.indicator.url.scheme\" | \"threat.indicator.url.subdomain\" | \"threat.indicator.url.top_level_domain\" | \"threat.indicator.url.username\" | \"threat.indicator.x509.alternative_names\" | \"threat.indicator.x509.issuer.common_name\" | \"threat.indicator.x509.issuer.country\" | \"threat.indicator.x509.issuer.distinguished_name\" | \"threat.indicator.x509.issuer.locality\" | \"threat.indicator.x509.issuer.organization\" | \"threat.indicator.x509.issuer.organizational_unit\" | \"threat.indicator.x509.issuer.state_or_province\" | \"threat.indicator.x509.not_after\" | \"threat.indicator.x509.not_before\" | \"threat.indicator.x509.public_key_algorithm\" | \"threat.indicator.x509.public_key_curve\" | \"threat.indicator.x509.public_key_exponent\" | \"threat.indicator.x509.public_key_size\" | \"threat.indicator.x509.serial_number\" | \"threat.indicator.x509.signature_algorithm\" | \"threat.indicator.x509.subject.common_name\" | \"threat.indicator.x509.subject.country\" | \"threat.indicator.x509.subject.distinguished_name\" | \"threat.indicator.x509.subject.locality\" | \"threat.indicator.x509.subject.organization\" | \"threat.indicator.x509.subject.organizational_unit\" | \"threat.indicator.x509.subject.state_or_province\" | \"threat.indicator.x509.version_number\" | \"threat.software.alias\" | \"threat.software.id\" | \"threat.software.name\" | \"threat.software.platforms\" | \"threat.software.reference\" | \"threat.software.type\" | \"threat.tactic.id\" | \"threat.tactic.name\" | \"threat.tactic.reference\" | \"threat.technique.id\" | \"threat.technique.name\" | \"threat.technique.reference\" | \"threat.technique.subtechnique.id\" | \"threat.technique.subtechnique.name\" | \"threat.technique.subtechnique.reference\" | \"tls.cipher\" | \"tls.client.certificate\" | \"tls.client.certificate_chain\" | \"tls.client.hash.md5\" | \"tls.client.hash.sha1\" | \"tls.client.hash.sha256\" | \"tls.client.issuer\" | \"tls.client.ja3\" | \"tls.client.not_after\" | \"tls.client.not_before\" | \"tls.client.server_name\" | \"tls.client.subject\" | \"tls.client.supported_ciphers\" | \"tls.client.x509.alternative_names\" | \"tls.client.x509.issuer.common_name\" | \"tls.client.x509.issuer.country\" | \"tls.client.x509.issuer.distinguished_name\" | \"tls.client.x509.issuer.locality\" | \"tls.client.x509.issuer.organization\" | \"tls.client.x509.issuer.organizational_unit\" | \"tls.client.x509.issuer.state_or_province\" | \"tls.client.x509.not_after\" | \"tls.client.x509.not_before\" | \"tls.client.x509.public_key_algorithm\" | \"tls.client.x509.public_key_curve\" | \"tls.client.x509.public_key_exponent\" | \"tls.client.x509.public_key_size\" | \"tls.client.x509.serial_number\" | \"tls.client.x509.signature_algorithm\" | \"tls.client.x509.subject.common_name\" | \"tls.client.x509.subject.country\" | \"tls.client.x509.subject.distinguished_name\" | \"tls.client.x509.subject.locality\" | \"tls.client.x509.subject.organization\" | \"tls.client.x509.subject.organizational_unit\" | \"tls.client.x509.subject.state_or_province\" | \"tls.client.x509.version_number\" | \"tls.curve\" | \"tls.established\" | \"tls.next_protocol\" | \"tls.resumed\" | \"tls.server.certificate\" | \"tls.server.certificate_chain\" | \"tls.server.hash.md5\" | \"tls.server.hash.sha1\" | \"tls.server.hash.sha256\" | \"tls.server.issuer\" | \"tls.server.ja3s\" | \"tls.server.not_after\" | \"tls.server.not_before\" | \"tls.server.subject\" | \"tls.server.x509.alternative_names\" | \"tls.server.x509.issuer.common_name\" | \"tls.server.x509.issuer.country\" | \"tls.server.x509.issuer.distinguished_name\" | \"tls.server.x509.issuer.locality\" | \"tls.server.x509.issuer.organization\" | \"tls.server.x509.issuer.organizational_unit\" | \"tls.server.x509.issuer.state_or_province\" | \"tls.server.x509.not_after\" | \"tls.server.x509.not_before\" | \"tls.server.x509.public_key_algorithm\" | \"tls.server.x509.public_key_curve\" | \"tls.server.x509.public_key_exponent\" | \"tls.server.x509.public_key_size\" | \"tls.server.x509.serial_number\" | \"tls.server.x509.signature_algorithm\" | \"tls.server.x509.subject.common_name\" | \"tls.server.x509.subject.country\" | \"tls.server.x509.subject.distinguished_name\" | \"tls.server.x509.subject.locality\" | \"tls.server.x509.subject.organization\" | \"tls.server.x509.subject.organizational_unit\" | \"tls.server.x509.subject.state_or_province\" | \"tls.server.x509.version_number\" | \"tls.version\" | \"tls.version_protocol\" | \"trace.id\" | \"transaction.id\" | \"url.domain\" | \"url.extension\" | \"url.fragment\" | \"url.full\" | \"url.original\" | \"url.password\" | \"url.path\" | \"url.port\" | \"url.query\" | \"url.registered_domain\" | \"url.scheme\" | \"url.subdomain\" | \"url.top_level_domain\" | \"url.username\" | \"user.changes.domain\" | \"user.changes.email\" | \"user.changes.full_name\" | \"user.changes.group.domain\" | \"user.changes.group.id\" | \"user.changes.group.name\" | \"user.changes.hash\" | \"user.changes.id\" | \"user.changes.name\" | \"user.changes.roles\" | \"user.domain\" | \"user.effective.domain\" | \"user.effective.email\" | \"user.effective.full_name\" | \"user.effective.group.domain\" | \"user.effective.group.id\" | \"user.effective.group.name\" | \"user.effective.hash\" | \"user.effective.id\" | \"user.effective.name\" | \"user.effective.roles\" | \"user.email\" | \"user.full_name\" | \"user.group.domain\" | \"user.group.id\" | \"user.group.name\" | \"user.hash\" | \"user.id\" | \"user.name\" | \"user.risk.calculated_level\" | \"user.risk.calculated_score\" | \"user.risk.calculated_score_norm\" | \"user.risk.static_level\" | \"user.risk.static_score\" | \"user.risk.static_score_norm\" | \"user.roles\" | \"user.target.domain\" | \"user.target.email\" | \"user.target.full_name\" | \"user.target.group.domain\" | \"user.target.group.id\" | \"user.target.group.name\" | \"user.target.hash\" | \"user.target.id\" | \"user.target.name\" | \"user.target.roles\" | \"user_agent.device.name\" | \"user_agent.name\" | \"user_agent.original\" | \"user_agent.os.family\" | \"user_agent.os.full\" | \"user_agent.os.kernel\" | \"user_agent.os.name\" | \"user_agent.os.platform\" | \"user_agent.os.type\" | \"user_agent.os.version\" | \"user_agent.version\" | \"vulnerability.category\" | \"vulnerability.classification\" | \"vulnerability.description\" | \"vulnerability.enumeration\" | \"vulnerability.id\" | \"vulnerability.reference\" | \"vulnerability.report_id\" | \"vulnerability.scanner.vendor\" | \"vulnerability.score.base\" | \"vulnerability.score.environmental\" | \"vulnerability.score.temporal\" | \"vulnerability.score.version\" | \"vulnerability.severity\" | (string & {}) | \"data_stream.dataset\" | \"data_stream.namespace\" | \"data_stream.type\" | \"dll.pe.sections.entropy\" | \"dll.pe.sections.name\" | \"dll.pe.sections.physical_size\" | \"dll.pe.sections.var_entropy\" | \"dll.pe.sections.virtual_size\" | \"dns.answers.class\" | \"dns.answers.data\" | \"dns.answers.name\" | \"dns.answers.ttl\" | \"dns.answers.type\" | \"email.attachments.file.extension\" | \"email.attachments.file.hash.md5\" | \"email.attachments.file.hash.sha1\" | \"email.attachments.file.hash.sha256\" | \"email.attachments.file.hash.sha384\" | \"email.attachments.file.hash.sha512\" | \"email.attachments.file.hash.ssdeep\" | \"email.attachments.file.hash.tlsh\" | \"email.attachments.file.mime_type\" | \"email.attachments.file.name\" | \"email.attachments.file.size\" | \"faas.trigger.request_id\" | \"faas.trigger.type\" | \"file.elf.sections.chi2\" | \"file.elf.sections.entropy\" | \"file.elf.sections.flags\" | \"file.elf.sections.name\" | \"file.elf.sections.physical_offset\" | \"file.elf.sections.physical_size\" | \"file.elf.sections.type\" | \"file.elf.sections.var_entropy\" | \"file.elf.sections.virtual_address\" | \"file.elf.sections.virtual_size\" | \"file.elf.segments.sections\" | \"file.elf.segments.type\" | \"file.macho.sections.entropy\" | \"file.macho.sections.name\" | \"file.macho.sections.physical_size\" | \"file.macho.sections.var_entropy\" | \"file.macho.sections.virtual_size\" | \"file.pe.sections.entropy\" | \"file.pe.sections.name\" | \"file.pe.sections.physical_size\" | \"file.pe.sections.var_entropy\" | \"file.pe.sections.virtual_size\" | \"log.syslog.appname\" | \"log.syslog.facility.code\" | \"log.syslog.facility.name\" | \"log.syslog.hostname\" | \"log.syslog.msgid\" | \"log.syslog.priority\" | \"log.syslog.procid\" | \"log.syslog.severity.code\" | \"log.syslog.severity.name\" | \"log.syslog.structured_data\" | \"log.syslog.version\" | \"network.inner.vlan.id\" | \"network.inner.vlan.name\" | \"observer.egress.interface.alias\" | \"observer.egress.interface.id\" | \"observer.egress.interface.name\" | \"observer.egress.vlan.id\" | \"observer.egress.vlan.name\" | \"observer.egress.zone\" | \"observer.ingress.interface.alias\" | \"observer.ingress.interface.id\" | \"observer.ingress.interface.name\" | \"observer.ingress.vlan.id\" | \"observer.ingress.vlan.name\" | \"observer.ingress.zone\" | \"process.elf.sections.chi2\" | \"process.elf.sections.entropy\" | \"process.elf.sections.flags\" | \"process.elf.sections.name\" | \"process.elf.sections.physical_offset\" | \"process.elf.sections.physical_size\" | \"process.elf.sections.type\" | \"process.elf.sections.var_entropy\" | \"process.elf.sections.virtual_address\" | \"process.elf.sections.virtual_size\" | \"process.elf.segments.sections\" | \"process.elf.segments.type\" | \"process.entry_leader.tty.char_device.major\" | \"process.entry_leader.tty.char_device.minor\" | \"process.group_leader.tty.char_device.major\" | \"process.group_leader.tty.char_device.minor\" | \"process.io.bytes_skipped\" | \"process.io.bytes_skipped.length\" | \"process.io.bytes_skipped.offset\" | \"process.io.max_bytes_per_process_exceeded\" | \"process.io.text\" | \"process.io.total_bytes_captured\" | \"process.io.total_bytes_skipped\" | \"process.io.type\" | \"process.macho.sections.entropy\" | \"process.macho.sections.name\" | \"process.macho.sections.physical_size\" | \"process.macho.sections.var_entropy\" | \"process.macho.sections.virtual_size\" | \"process.parent.elf.sections.chi2\" | \"process.parent.elf.sections.entropy\" | \"process.parent.elf.sections.flags\" | \"process.parent.elf.sections.name\" | \"process.parent.elf.sections.physical_offset\" | \"process.parent.elf.sections.physical_size\" | \"process.parent.elf.sections.type\" | \"process.parent.elf.sections.var_entropy\" | \"process.parent.elf.sections.virtual_address\" | \"process.parent.elf.sections.virtual_size\" | \"process.parent.elf.segments.sections\" | \"process.parent.elf.segments.type\" | \"process.parent.macho.sections.entropy\" | \"process.parent.macho.sections.name\" | \"process.parent.macho.sections.physical_size\" | \"process.parent.macho.sections.var_entropy\" | \"process.parent.macho.sections.virtual_size\" | \"process.parent.pe.sections.entropy\" | \"process.parent.pe.sections.name\" | \"process.parent.pe.sections.physical_size\" | \"process.parent.pe.sections.var_entropy\" | \"process.parent.pe.sections.virtual_size\" | \"process.parent.tty.char_device.major\" | \"process.parent.tty.char_device.minor\" | \"process.pe.sections.entropy\" | \"process.pe.sections.name\" | \"process.pe.sections.physical_size\" | \"process.pe.sections.var_entropy\" | \"process.pe.sections.virtual_size\" | \"process.session_leader.tty.char_device.major\" | \"process.session_leader.tty.char_device.minor\" | \"process.tty.char_device.major\" | \"process.tty.char_device.minor\" | \"process.tty.columns\" | \"process.tty.rows\" | \"threat.enrichments.indicator\" | \"threat.enrichments.indicator.as.number\" | \"threat.enrichments.indicator.as.organization.name\" | \"threat.enrichments.indicator.confidence\" | \"threat.enrichments.indicator.description\" | \"threat.enrichments.indicator.email.address\" | \"threat.enrichments.indicator.file.accessed\" | \"threat.enrichments.indicator.file.attributes\" | \"threat.enrichments.indicator.file.code_signature.digest_algorithm\" | \"threat.enrichments.indicator.file.code_signature.exists\" | \"threat.enrichments.indicator.file.code_signature.signing_id\" | \"threat.enrichments.indicator.file.code_signature.status\" | \"threat.enrichments.indicator.file.code_signature.subject_name\" | \"threat.enrichments.indicator.file.code_signature.team_id\" | \"threat.enrichments.indicator.file.code_signature.timestamp\" | \"threat.enrichments.indicator.file.code_signature.trusted\" | \"threat.enrichments.indicator.file.code_signature.valid\" | \"threat.enrichments.indicator.file.created\" | \"threat.enrichments.indicator.file.ctime\" | \"threat.enrichments.indicator.file.device\" | \"threat.enrichments.indicator.file.directory\" | \"threat.enrichments.indicator.file.drive_letter\" | \"threat.enrichments.indicator.file.elf.architecture\" | \"threat.enrichments.indicator.file.elf.byte_order\" | \"threat.enrichments.indicator.file.elf.cpu_type\" | \"threat.enrichments.indicator.file.elf.creation_date\" | \"threat.enrichments.indicator.file.elf.exports\" | \"threat.enrichments.indicator.file.elf.go_import_hash\" | \"threat.enrichments.indicator.file.elf.go_imports\" | \"threat.enrichments.indicator.file.elf.go_imports_names_entropy\" | \"threat.enrichments.indicator.file.elf.go_imports_names_var_entropy\" | \"threat.enrichments.indicator.file.elf.go_stripped\" | \"threat.enrichments.indicator.file.elf.header.abi_version\" | \"threat.enrichments.indicator.file.elf.header.class\" | \"threat.enrichments.indicator.file.elf.header.data\" | \"threat.enrichments.indicator.file.elf.header.entrypoint\" | \"threat.enrichments.indicator.file.elf.header.object_version\" | \"threat.enrichments.indicator.file.elf.header.os_abi\" | \"threat.enrichments.indicator.file.elf.header.type\" | \"threat.enrichments.indicator.file.elf.header.version\" | \"threat.enrichments.indicator.file.elf.import_hash\" | \"threat.enrichments.indicator.file.elf.imports\" | \"threat.enrichments.indicator.file.elf.imports_names_entropy\" | \"threat.enrichments.indicator.file.elf.imports_names_var_entropy\" | \"threat.enrichments.indicator.file.elf.sections\" | \"threat.enrichments.indicator.file.elf.sections.chi2\" | \"threat.enrichments.indicator.file.elf.sections.entropy\" | \"threat.enrichments.indicator.file.elf.sections.flags\" | \"threat.enrichments.indicator.file.elf.sections.name\" | \"threat.enrichments.indicator.file.elf.sections.physical_offset\" | \"threat.enrichments.indicator.file.elf.sections.physical_size\" | \"threat.enrichments.indicator.file.elf.sections.type\" | \"threat.enrichments.indicator.file.elf.sections.var_entropy\" | \"threat.enrichments.indicator.file.elf.sections.virtual_address\" | \"threat.enrichments.indicator.file.elf.sections.virtual_size\" | \"threat.enrichments.indicator.file.elf.segments\" | \"threat.enrichments.indicator.file.elf.segments.sections\" | \"threat.enrichments.indicator.file.elf.segments.type\" | \"threat.enrichments.indicator.file.elf.shared_libraries\" | \"threat.enrichments.indicator.file.elf.telfhash\" | \"threat.enrichments.indicator.file.extension\" | \"threat.enrichments.indicator.file.fork_name\" | \"threat.enrichments.indicator.file.gid\" | \"threat.enrichments.indicator.file.group\" | \"threat.enrichments.indicator.file.hash.md5\" | \"threat.enrichments.indicator.file.hash.sha1\" | \"threat.enrichments.indicator.file.hash.sha256\" | \"threat.enrichments.indicator.file.hash.sha384\" | \"threat.enrichments.indicator.file.hash.sha512\" | \"threat.enrichments.indicator.file.hash.ssdeep\" | \"threat.enrichments.indicator.file.hash.tlsh\" | \"threat.enrichments.indicator.file.inode\" | \"threat.enrichments.indicator.file.mime_type\" | \"threat.enrichments.indicator.file.mode\" | \"threat.enrichments.indicator.file.mtime\" | \"threat.enrichments.indicator.file.name\" | \"threat.enrichments.indicator.file.owner\" | \"threat.enrichments.indicator.file.path\" | \"threat.enrichments.indicator.file.pe.architecture\" | \"threat.enrichments.indicator.file.pe.company\" | \"threat.enrichments.indicator.file.pe.description\" | \"threat.enrichments.indicator.file.pe.file_version\" | \"threat.enrichments.indicator.file.pe.go_import_hash\" | \"threat.enrichments.indicator.file.pe.go_imports\" | \"threat.enrichments.indicator.file.pe.go_imports_names_entropy\" | \"threat.enrichments.indicator.file.pe.go_imports_names_var_entropy\" | \"threat.enrichments.indicator.file.pe.go_stripped\" | \"threat.enrichments.indicator.file.pe.imphash\" | \"threat.enrichments.indicator.file.pe.import_hash\" | \"threat.enrichments.indicator.file.pe.imports\" | \"threat.enrichments.indicator.file.pe.imports_names_entropy\" | \"threat.enrichments.indicator.file.pe.imports_names_var_entropy\" | \"threat.enrichments.indicator.file.pe.original_file_name\" | \"threat.enrichments.indicator.file.pe.pehash\" | \"threat.enrichments.indicator.file.pe.product\" | \"threat.enrichments.indicator.file.pe.sections\" | \"threat.enrichments.indicator.file.pe.sections.entropy\" | \"threat.enrichments.indicator.file.pe.sections.name\" | \"threat.enrichments.indicator.file.pe.sections.physical_size\" | \"threat.enrichments.indicator.file.pe.sections.var_entropy\" | \"threat.enrichments.indicator.file.pe.sections.virtual_size\" | \"threat.enrichments.indicator.file.size\" | \"threat.enrichments.indicator.file.target_path\" | \"threat.enrichments.indicator.file.type\" | \"threat.enrichments.indicator.file.uid\" | \"threat.enrichments.indicator.file.x509.alternative_names\" | \"threat.enrichments.indicator.file.x509.issuer.common_name\" | \"threat.enrichments.indicator.file.x509.issuer.country\" | \"threat.enrichments.indicator.file.x509.issuer.distinguished_name\" | \"threat.enrichments.indicator.file.x509.issuer.locality\" | \"threat.enrichments.indicator.file.x509.issuer.organization\" | \"threat.enrichments.indicator.file.x509.issuer.organizational_unit\" | \"threat.enrichments.indicator.file.x509.issuer.state_or_province\" | \"threat.enrichments.indicator.file.x509.not_after\" | \"threat.enrichments.indicator.file.x509.not_before\" | \"threat.enrichments.indicator.file.x509.public_key_algorithm\" | \"threat.enrichments.indicator.file.x509.public_key_curve\" | \"threat.enrichments.indicator.file.x509.public_key_exponent\" | \"threat.enrichments.indicator.file.x509.public_key_size\" | \"threat.enrichments.indicator.file.x509.serial_number\" | \"threat.enrichments.indicator.file.x509.signature_algorithm\" | \"threat.enrichments.indicator.file.x509.subject.common_name\" | \"threat.enrichments.indicator.file.x509.subject.country\" | \"threat.enrichments.indicator.file.x509.subject.distinguished_name\" | \"threat.enrichments.indicator.file.x509.subject.locality\" | \"threat.enrichments.indicator.file.x509.subject.organization\" | \"threat.enrichments.indicator.file.x509.subject.organizational_unit\" | \"threat.enrichments.indicator.file.x509.subject.state_or_province\" | \"threat.enrichments.indicator.file.x509.version_number\" | \"threat.enrichments.indicator.first_seen\" | \"threat.enrichments.indicator.geo.city_name\" | \"threat.enrichments.indicator.geo.continent_code\" | \"threat.enrichments.indicator.geo.continent_name\" | \"threat.enrichments.indicator.geo.country_iso_code\" | \"threat.enrichments.indicator.geo.country_name\" | \"threat.enrichments.indicator.geo.location\" | \"threat.enrichments.indicator.geo.name\" | \"threat.enrichments.indicator.geo.postal_code\" | \"threat.enrichments.indicator.geo.region_iso_code\" | \"threat.enrichments.indicator.geo.region_name\" | \"threat.enrichments.indicator.geo.timezone\" | \"threat.enrichments.indicator.ip\" | \"threat.enrichments.indicator.last_seen\" | \"threat.enrichments.indicator.marking.tlp\" | \"threat.enrichments.indicator.marking.tlp_version\" | \"threat.enrichments.indicator.modified_at\" | \"threat.enrichments.indicator.name\" | \"threat.enrichments.indicator.port\" | \"threat.enrichments.indicator.provider\" | \"threat.enrichments.indicator.reference\" | \"threat.enrichments.indicator.registry.data.bytes\" | \"threat.enrichments.indicator.registry.data.strings\" | \"threat.enrichments.indicator.registry.data.type\" | \"threat.enrichments.indicator.registry.hive\" | \"threat.enrichments.indicator.registry.key\" | \"threat.enrichments.indicator.registry.path\" | \"threat.enrichments.indicator.registry.value\" | \"threat.enrichments.indicator.scanner_stats\" | \"threat.enrichments.indicator.sightings\" | \"threat.enrichments.indicator.type\" | \"threat.enrichments.indicator.url.domain\" | \"threat.enrichments.indicator.url.extension\" | \"threat.enrichments.indicator.url.fragment\" | \"threat.enrichments.indicator.url.full\" | \"threat.enrichments.indicator.url.original\" | \"threat.enrichments.indicator.url.password\" | \"threat.enrichments.indicator.url.path\" | \"threat.enrichments.indicator.url.port\" | \"threat.enrichments.indicator.url.query\" | \"threat.enrichments.indicator.url.registered_domain\" | \"threat.enrichments.indicator.url.scheme\" | \"threat.enrichments.indicator.url.subdomain\" | \"threat.enrichments.indicator.url.top_level_domain\" | \"threat.enrichments.indicator.url.username\" | \"threat.enrichments.indicator.x509.alternative_names\" | \"threat.enrichments.indicator.x509.issuer.common_name\" | \"threat.enrichments.indicator.x509.issuer.country\" | \"threat.enrichments.indicator.x509.issuer.distinguished_name\" | \"threat.enrichments.indicator.x509.issuer.locality\" | \"threat.enrichments.indicator.x509.issuer.organization\" | \"threat.enrichments.indicator.x509.issuer.organizational_unit\" | \"threat.enrichments.indicator.x509.issuer.state_or_province\" | \"threat.enrichments.indicator.x509.not_after\" | \"threat.enrichments.indicator.x509.not_before\" | \"threat.enrichments.indicator.x509.public_key_algorithm\" | \"threat.enrichments.indicator.x509.public_key_curve\" | \"threat.enrichments.indicator.x509.public_key_exponent\" | \"threat.enrichments.indicator.x509.public_key_size\" | \"threat.enrichments.indicator.x509.serial_number\" | \"threat.enrichments.indicator.x509.signature_algorithm\" | \"threat.enrichments.indicator.x509.subject.common_name\" | \"threat.enrichments.indicator.x509.subject.country\" | \"threat.enrichments.indicator.x509.subject.distinguished_name\" | \"threat.enrichments.indicator.x509.subject.locality\" | \"threat.enrichments.indicator.x509.subject.organization\" | \"threat.enrichments.indicator.x509.subject.organizational_unit\" | \"threat.enrichments.indicator.x509.subject.state_or_province\" | \"threat.enrichments.indicator.x509.version_number\" | \"threat.enrichments.matched.atomic\" | \"threat.enrichments.matched.field\" | \"threat.enrichments.matched.id\" | \"threat.enrichments.matched.index\" | \"threat.enrichments.matched.occurred\" | \"threat.enrichments.matched.type\" | \"threat.indicator.file.elf.sections.chi2\" | \"threat.indicator.file.elf.sections.entropy\" | \"threat.indicator.file.elf.sections.flags\" | \"threat.indicator.file.elf.sections.name\" | \"threat.indicator.file.elf.sections.physical_offset\" | \"threat.indicator.file.elf.sections.physical_size\" | \"threat.indicator.file.elf.sections.type\" | \"threat.indicator.file.elf.sections.var_entropy\" | \"threat.indicator.file.elf.sections.virtual_address\" | \"threat.indicator.file.elf.sections.virtual_size\" | \"threat.indicator.file.elf.segments.sections\" | \"threat.indicator.file.elf.segments.type\" | \"threat.indicator.file.pe.sections.entropy\" | \"threat.indicator.file.pe.sections.name\" | \"threat.indicator.file.pe.sections.physical_size\" | \"threat.indicator.file.pe.sections.var_entropy\" | \"threat.indicator.file.pe.sections.virtual_size\"" + "\"@timestamp\" | \"event.sequence\" | \"event.start\" | \"event.end\" | \"event.provider\" | \"event.duration\" | \"event.action\" | \"message\" | \"event.outcome\" | \"tags\" | \"event.kind\" | \"agent.name\" | \"container.id\" | \"host.name\" | \"labels\" | \"service.environment\" | \"service.name\" | \"ecs.version\" | \"agent.build.original\" | \"agent.ephemeral_id\" | \"agent.id\" | \"agent.type\" | \"agent.version\" | \"client.address\" | \"client.as.number\" | \"client.as.organization.name\" | \"client.bytes\" | \"client.domain\" | \"client.geo.city_name\" | \"client.geo.continent_code\" | \"client.geo.continent_name\" | \"client.geo.country_iso_code\" | \"client.geo.country_name\" | \"client.geo.location\" | \"client.geo.name\" | \"client.geo.postal_code\" | \"client.geo.region_iso_code\" | \"client.geo.region_name\" | \"client.geo.timezone\" | \"client.ip\" | \"client.mac\" | \"client.nat.ip\" | \"client.nat.port\" | \"client.packets\" | \"client.port\" | \"client.registered_domain\" | \"client.subdomain\" | \"client.top_level_domain\" | \"client.user.domain\" | \"client.user.email\" | \"client.user.full_name\" | \"client.user.group.domain\" | \"client.user.group.id\" | \"client.user.group.name\" | \"client.user.hash\" | \"client.user.id\" | \"client.user.name\" | \"client.user.roles\" | \"cloud.account.id\" | \"cloud.account.name\" | \"cloud.availability_zone\" | \"cloud.instance.id\" | \"cloud.instance.name\" | \"cloud.machine.type\" | \"cloud.origin.account.id\" | \"cloud.origin.account.name\" | \"cloud.origin.availability_zone\" | \"cloud.origin.instance.id\" | \"cloud.origin.instance.name\" | \"cloud.origin.machine.type\" | \"cloud.origin.project.id\" | \"cloud.origin.project.name\" | \"cloud.origin.provider\" | \"cloud.origin.region\" | \"cloud.origin.service.name\" | \"cloud.project.id\" | \"cloud.project.name\" | \"cloud.provider\" | \"cloud.region\" | \"cloud.service.name\" | \"cloud.target.account.id\" | \"cloud.target.account.name\" | \"cloud.target.availability_zone\" | \"cloud.target.instance.id\" | \"cloud.target.instance.name\" | \"cloud.target.machine.type\" | \"cloud.target.project.id\" | \"cloud.target.project.name\" | \"cloud.target.provider\" | \"cloud.target.region\" | \"cloud.target.service.name\" | \"container.cpu.usage\" | \"container.disk.read.bytes\" | \"container.disk.write.bytes\" | \"container.image.hash.all\" | \"container.image.name\" | \"container.image.tag\" | \"container.labels\" | \"container.memory.usage\" | \"container.name\" | \"container.network.egress.bytes\" | \"container.network.ingress.bytes\" | \"container.runtime\" | \"container.security_context.privileged\" | \"destination.address\" | \"destination.as.number\" | \"destination.as.organization.name\" | \"destination.bytes\" | \"destination.domain\" | \"destination.geo.city_name\" | \"destination.geo.continent_code\" | \"destination.geo.continent_name\" | \"destination.geo.country_iso_code\" | \"destination.geo.country_name\" | \"destination.geo.location\" | \"destination.geo.name\" | \"destination.geo.postal_code\" | \"destination.geo.region_iso_code\" | \"destination.geo.region_name\" | \"destination.geo.timezone\" | \"destination.ip\" | \"destination.mac\" | \"destination.nat.ip\" | \"destination.nat.port\" | \"destination.packets\" | \"destination.port\" | \"destination.registered_domain\" | \"destination.subdomain\" | \"destination.top_level_domain\" | \"destination.user.domain\" | \"destination.user.email\" | \"destination.user.full_name\" | \"destination.user.group.domain\" | \"destination.user.group.id\" | \"destination.user.group.name\" | \"destination.user.hash\" | \"destination.user.id\" | \"destination.user.name\" | \"destination.user.roles\" | \"device.id\" | \"device.manufacturer\" | \"device.model.identifier\" | \"device.model.name\" | \"dll.code_signature.digest_algorithm\" | \"dll.code_signature.exists\" | \"dll.code_signature.signing_id\" | \"dll.code_signature.status\" | \"dll.code_signature.subject_name\" | \"dll.code_signature.team_id\" | \"dll.code_signature.timestamp\" | \"dll.code_signature.trusted\" | \"dll.code_signature.valid\" | \"dll.hash.md5\" | \"dll.hash.sha1\" | \"dll.hash.sha256\" | \"dll.hash.sha384\" | \"dll.hash.sha512\" | \"dll.hash.ssdeep\" | \"dll.hash.tlsh\" | \"dll.name\" | \"dll.path\" | \"dll.pe.architecture\" | \"dll.pe.company\" | \"dll.pe.description\" | \"dll.pe.file_version\" | \"dll.pe.go_import_hash\" | \"dll.pe.go_imports\" | \"dll.pe.go_imports_names_entropy\" | \"dll.pe.go_imports_names_var_entropy\" | \"dll.pe.go_stripped\" | \"dll.pe.imphash\" | \"dll.pe.import_hash\" | \"dll.pe.imports\" | \"dll.pe.imports_names_entropy\" | \"dll.pe.imports_names_var_entropy\" | \"dll.pe.original_file_name\" | \"dll.pe.pehash\" | \"dll.pe.product\" | \"dll.pe.sections\" | \"dns.answers\" | \"dns.header_flags\" | \"dns.id\" | \"dns.op_code\" | \"dns.question.class\" | \"dns.question.name\" | \"dns.question.registered_domain\" | \"dns.question.subdomain\" | \"dns.question.top_level_domain\" | \"dns.question.type\" | \"dns.resolved_ip\" | \"dns.response_code\" | \"dns.type\" | \"email.attachments\" | \"file.extension\" | \"file.hash.md5\" | \"file.hash.sha1\" | \"file.hash.sha256\" | \"file.hash.sha384\" | \"file.hash.sha512\" | \"file.hash.ssdeep\" | \"file.hash.tlsh\" | \"file.mime_type\" | \"file.name\" | \"file.size\" | \"email.bcc.address\" | \"email.cc.address\" | \"email.content_type\" | \"email.delivery_timestamp\" | \"email.direction\" | \"email.from.address\" | \"email.local_id\" | \"email.message_id\" | \"email.origination_timestamp\" | \"email.reply_to.address\" | \"email.sender.address\" | \"email.subject\" | \"email.to.address\" | \"email.x_mailer\" | \"error.code\" | \"error.id\" | \"error.message\" | \"error.stack_trace\" | \"error.type\" | \"event.agent_id_status\" | \"event.category\" | \"event.code\" | \"event.created\" | \"event.dataset\" | \"event.hash\" | \"event.id\" | \"event.ingested\" | \"event.module\" | \"event.original\" | \"event.reason\" | \"event.reference\" | \"event.risk_score\" | \"event.risk_score_norm\" | \"event.severity\" | \"event.timezone\" | \"event.type\" | \"event.url\" | \"faas.coldstart\" | \"faas.execution\" | \"faas.id\" | \"faas.name\" | \"faas.version\" | \"file.accessed\" | \"file.attributes\" | \"file.code_signature.digest_algorithm\" | \"file.code_signature.exists\" | \"file.code_signature.signing_id\" | \"file.code_signature.status\" | \"file.code_signature.subject_name\" | \"file.code_signature.team_id\" | \"file.code_signature.timestamp\" | \"file.code_signature.trusted\" | \"file.code_signature.valid\" | \"file.created\" | \"file.ctime\" | \"file.device\" | \"file.directory\" | \"file.drive_letter\" | \"file.elf.architecture\" | \"file.elf.byte_order\" | \"file.elf.cpu_type\" | \"file.elf.creation_date\" | \"file.elf.exports\" | \"file.elf.go_import_hash\" | \"file.elf.go_imports\" | \"file.elf.go_imports_names_entropy\" | \"file.elf.go_imports_names_var_entropy\" | \"file.elf.go_stripped\" | \"file.elf.header.abi_version\" | \"file.elf.header.class\" | \"file.elf.header.data\" | \"file.elf.header.entrypoint\" | \"file.elf.header.object_version\" | \"file.elf.header.os_abi\" | \"file.elf.header.type\" | \"file.elf.header.version\" | \"file.elf.import_hash\" | \"file.elf.imports\" | \"file.elf.imports_names_entropy\" | \"file.elf.imports_names_var_entropy\" | \"file.elf.sections\" | \"file.elf.segments\" | \"file.elf.shared_libraries\" | \"file.elf.telfhash\" | \"file.fork_name\" | \"file.gid\" | \"file.group\" | \"file.inode\" | \"file.macho.go_import_hash\" | \"file.macho.go_imports\" | \"file.macho.go_imports_names_entropy\" | \"file.macho.go_imports_names_var_entropy\" | \"file.macho.go_stripped\" | \"file.macho.import_hash\" | \"file.macho.imports\" | \"file.macho.imports_names_entropy\" | \"file.macho.imports_names_var_entropy\" | \"file.macho.sections\" | \"file.macho.symhash\" | \"file.mode\" | \"file.mtime\" | \"file.owner\" | \"file.path\" | \"file.pe.architecture\" | \"file.pe.company\" | \"file.pe.description\" | \"file.pe.file_version\" | \"file.pe.go_import_hash\" | \"file.pe.go_imports\" | \"file.pe.go_imports_names_entropy\" | \"file.pe.go_imports_names_var_entropy\" | \"file.pe.go_stripped\" | \"file.pe.imphash\" | \"file.pe.import_hash\" | \"file.pe.imports\" | \"file.pe.imports_names_entropy\" | \"file.pe.imports_names_var_entropy\" | \"file.pe.original_file_name\" | \"file.pe.pehash\" | \"file.pe.product\" | \"file.pe.sections\" | \"file.target_path\" | \"file.type\" | \"file.uid\" | \"file.x509.alternative_names\" | \"file.x509.issuer.common_name\" | \"file.x509.issuer.country\" | \"file.x509.issuer.distinguished_name\" | \"file.x509.issuer.locality\" | \"file.x509.issuer.organization\" | \"file.x509.issuer.organizational_unit\" | \"file.x509.issuer.state_or_province\" | \"file.x509.not_after\" | \"file.x509.not_before\" | \"file.x509.public_key_algorithm\" | \"file.x509.public_key_curve\" | \"file.x509.public_key_exponent\" | \"file.x509.public_key_size\" | \"file.x509.serial_number\" | \"file.x509.signature_algorithm\" | \"file.x509.subject.common_name\" | \"file.x509.subject.country\" | \"file.x509.subject.distinguished_name\" | \"file.x509.subject.locality\" | \"file.x509.subject.organization\" | \"file.x509.subject.organizational_unit\" | \"file.x509.subject.state_or_province\" | \"file.x509.version_number\" | \"group.domain\" | \"group.id\" | \"group.name\" | \"host.architecture\" | \"host.boot.id\" | \"host.cpu.usage\" | \"host.disk.read.bytes\" | \"host.disk.write.bytes\" | \"host.domain\" | \"host.geo.city_name\" | \"host.geo.continent_code\" | \"host.geo.continent_name\" | \"host.geo.country_iso_code\" | \"host.geo.country_name\" | \"host.geo.location\" | \"host.geo.name\" | \"host.geo.postal_code\" | \"host.geo.region_iso_code\" | \"host.geo.region_name\" | \"host.geo.timezone\" | \"host.hostname\" | \"host.id\" | \"host.ip\" | \"host.mac\" | \"host.network.egress.bytes\" | \"host.network.egress.packets\" | \"host.network.ingress.bytes\" | \"host.network.ingress.packets\" | \"host.os.family\" | \"host.os.full\" | \"host.os.kernel\" | \"host.os.name\" | \"host.os.platform\" | \"host.os.type\" | \"host.os.version\" | \"host.pid_ns_ino\" | \"host.risk.calculated_level\" | \"host.risk.calculated_score\" | \"host.risk.calculated_score_norm\" | \"host.risk.static_level\" | \"host.risk.static_score\" | \"host.risk.static_score_norm\" | \"host.type\" | \"host.uptime\" | \"http.request.body.bytes\" | \"http.request.body.content\" | \"http.request.bytes\" | \"http.request.id\" | \"http.request.method\" | \"http.request.mime_type\" | \"http.request.referrer\" | \"http.response.body.bytes\" | \"http.response.body.content\" | \"http.response.bytes\" | \"http.response.mime_type\" | \"http.response.status_code\" | \"http.version\" | \"log.file.path\" | \"log.level\" | \"log.logger\" | \"log.origin.file.line\" | \"log.origin.file.name\" | \"log.origin.function\" | \"log.syslog\" | \"network.application\" | \"network.bytes\" | \"network.community_id\" | \"network.direction\" | \"network.forwarded_ip\" | \"network.iana_number\" | \"network.inner\" | \"network.name\" | \"network.packets\" | \"network.protocol\" | \"network.transport\" | \"network.type\" | \"network.vlan.id\" | \"network.vlan.name\" | \"observer.egress\" | \"observer.geo.city_name\" | \"observer.geo.continent_code\" | \"observer.geo.continent_name\" | \"observer.geo.country_iso_code\" | \"observer.geo.country_name\" | \"observer.geo.location\" | \"observer.geo.name\" | \"observer.geo.postal_code\" | \"observer.geo.region_iso_code\" | \"observer.geo.region_name\" | \"observer.geo.timezone\" | \"observer.hostname\" | \"observer.ingress\" | \"observer.ip\" | \"observer.mac\" | \"observer.name\" | \"observer.os.family\" | \"observer.os.full\" | \"observer.os.kernel\" | \"observer.os.name\" | \"observer.os.platform\" | \"observer.os.type\" | \"observer.os.version\" | \"observer.product\" | \"observer.serial_number\" | \"observer.type\" | \"observer.vendor\" | \"observer.version\" | \"orchestrator.api_version\" | \"orchestrator.cluster.id\" | \"orchestrator.cluster.name\" | \"orchestrator.cluster.url\" | \"orchestrator.cluster.version\" | \"orchestrator.namespace\" | \"orchestrator.organization\" | \"orchestrator.resource.annotation\" | \"orchestrator.resource.id\" | \"orchestrator.resource.ip\" | \"orchestrator.resource.label\" | \"orchestrator.resource.name\" | \"orchestrator.resource.parent.type\" | \"orchestrator.resource.type\" | \"orchestrator.type\" | \"organization.id\" | \"organization.name\" | \"package.architecture\" | \"package.build_version\" | \"package.checksum\" | \"package.description\" | \"package.install_scope\" | \"package.installed\" | \"package.license\" | \"package.name\" | \"package.path\" | \"package.reference\" | \"package.size\" | \"package.type\" | \"package.version\" | \"process.args\" | \"process.args_count\" | \"process.code_signature.digest_algorithm\" | \"process.code_signature.exists\" | \"process.code_signature.signing_id\" | \"process.code_signature.status\" | \"process.code_signature.subject_name\" | \"process.code_signature.team_id\" | \"process.code_signature.timestamp\" | \"process.code_signature.trusted\" | \"process.code_signature.valid\" | \"process.command_line\" | \"process.elf.architecture\" | \"process.elf.byte_order\" | \"process.elf.cpu_type\" | \"process.elf.creation_date\" | \"process.elf.exports\" | \"process.elf.go_import_hash\" | \"process.elf.go_imports\" | \"process.elf.go_imports_names_entropy\" | \"process.elf.go_imports_names_var_entropy\" | \"process.elf.go_stripped\" | \"process.elf.header.abi_version\" | \"process.elf.header.class\" | \"process.elf.header.data\" | \"process.elf.header.entrypoint\" | \"process.elf.header.object_version\" | \"process.elf.header.os_abi\" | \"process.elf.header.type\" | \"process.elf.header.version\" | \"process.elf.import_hash\" | \"process.elf.imports\" | \"process.elf.imports_names_entropy\" | \"process.elf.imports_names_var_entropy\" | \"process.elf.sections\" | \"process.elf.segments\" | \"process.elf.shared_libraries\" | \"process.elf.telfhash\" | \"process.end\" | \"process.entity_id\" | \"process.entry_leader.args\" | \"process.entry_leader.args_count\" | \"process.entry_leader.attested_groups.name\" | \"process.entry_leader.attested_user.id\" | \"process.entry_leader.attested_user.name\" | \"process.entry_leader.command_line\" | \"process.entry_leader.entity_id\" | \"process.entry_leader.entry_meta.source.ip\" | \"process.entry_leader.entry_meta.type\" | \"process.entry_leader.executable\" | \"process.entry_leader.group.id\" | \"process.entry_leader.group.name\" | \"process.entry_leader.interactive\" | \"process.entry_leader.name\" | \"process.entry_leader.parent.entity_id\" | \"process.entry_leader.parent.pid\" | \"process.entry_leader.parent.session_leader.entity_id\" | \"process.entry_leader.parent.session_leader.pid\" | \"process.entry_leader.parent.session_leader.start\" | \"process.entry_leader.parent.session_leader.vpid\" | \"process.entry_leader.parent.start\" | \"process.entry_leader.parent.vpid\" | \"process.entry_leader.pid\" | \"process.entry_leader.real_group.id\" | \"process.entry_leader.real_group.name\" | \"process.entry_leader.real_user.id\" | \"process.entry_leader.real_user.name\" | \"process.entry_leader.same_as_process\" | \"process.entry_leader.saved_group.id\" | \"process.entry_leader.saved_group.name\" | \"process.entry_leader.saved_user.id\" | \"process.entry_leader.saved_user.name\" | \"process.entry_leader.start\" | \"process.entry_leader.supplemental_groups.id\" | \"process.entry_leader.supplemental_groups.name\" | \"process.entry_leader.tty\" | \"process.entry_leader.user.id\" | \"process.entry_leader.user.name\" | \"process.entry_leader.vpid\" | \"process.entry_leader.working_directory\" | \"process.env_vars\" | \"process.executable\" | \"process.exit_code\" | \"process.group_leader.args\" | \"process.group_leader.args_count\" | \"process.group_leader.command_line\" | \"process.group_leader.entity_id\" | \"process.group_leader.executable\" | \"process.group_leader.group.id\" | \"process.group_leader.group.name\" | \"process.group_leader.interactive\" | \"process.group_leader.name\" | \"process.group_leader.pid\" | \"process.group_leader.real_group.id\" | \"process.group_leader.real_group.name\" | \"process.group_leader.real_user.id\" | \"process.group_leader.real_user.name\" | \"process.group_leader.same_as_process\" | \"process.group_leader.saved_group.id\" | \"process.group_leader.saved_group.name\" | \"process.group_leader.saved_user.id\" | \"process.group_leader.saved_user.name\" | \"process.group_leader.start\" | \"process.group_leader.supplemental_groups.id\" | \"process.group_leader.supplemental_groups.name\" | \"process.group_leader.tty\" | \"process.group_leader.user.id\" | \"process.group_leader.user.name\" | \"process.group_leader.vpid\" | \"process.group_leader.working_directory\" | \"process.hash.md5\" | \"process.hash.sha1\" | \"process.hash.sha256\" | \"process.hash.sha384\" | \"process.hash.sha512\" | \"process.hash.ssdeep\" | \"process.hash.tlsh\" | \"process.interactive\" | \"process.io\" | \"process.macho.go_import_hash\" | \"process.macho.go_imports\" | \"process.macho.go_imports_names_entropy\" | \"process.macho.go_imports_names_var_entropy\" | \"process.macho.go_stripped\" | \"process.macho.import_hash\" | \"process.macho.imports\" | \"process.macho.imports_names_entropy\" | \"process.macho.imports_names_var_entropy\" | \"process.macho.sections\" | \"process.macho.symhash\" | \"process.name\" | \"process.parent.args\" | \"process.parent.args_count\" | \"process.parent.code_signature.digest_algorithm\" | \"process.parent.code_signature.exists\" | \"process.parent.code_signature.signing_id\" | \"process.parent.code_signature.status\" | \"process.parent.code_signature.subject_name\" | \"process.parent.code_signature.team_id\" | \"process.parent.code_signature.timestamp\" | \"process.parent.code_signature.trusted\" | \"process.parent.code_signature.valid\" | \"process.parent.command_line\" | \"process.parent.elf.architecture\" | \"process.parent.elf.byte_order\" | \"process.parent.elf.cpu_type\" | \"process.parent.elf.creation_date\" | \"process.parent.elf.exports\" | \"process.parent.elf.go_import_hash\" | \"process.parent.elf.go_imports\" | \"process.parent.elf.go_imports_names_entropy\" | \"process.parent.elf.go_imports_names_var_entropy\" | \"process.parent.elf.go_stripped\" | \"process.parent.elf.header.abi_version\" | \"process.parent.elf.header.class\" | \"process.parent.elf.header.data\" | \"process.parent.elf.header.entrypoint\" | \"process.parent.elf.header.object_version\" | \"process.parent.elf.header.os_abi\" | \"process.parent.elf.header.type\" | \"process.parent.elf.header.version\" | \"process.parent.elf.import_hash\" | \"process.parent.elf.imports\" | \"process.parent.elf.imports_names_entropy\" | \"process.parent.elf.imports_names_var_entropy\" | \"process.parent.elf.sections\" | \"process.parent.elf.segments\" | \"process.parent.elf.shared_libraries\" | \"process.parent.elf.telfhash\" | \"process.parent.end\" | \"process.parent.entity_id\" | \"process.parent.executable\" | \"process.parent.exit_code\" | \"process.parent.group.id\" | \"process.parent.group.name\" | \"process.parent.group_leader.entity_id\" | \"process.parent.group_leader.pid\" | \"process.parent.group_leader.start\" | \"process.parent.group_leader.vpid\" | \"process.parent.hash.md5\" | \"process.parent.hash.sha1\" | \"process.parent.hash.sha256\" | \"process.parent.hash.sha384\" | \"process.parent.hash.sha512\" | \"process.parent.hash.ssdeep\" | \"process.parent.hash.tlsh\" | \"process.parent.interactive\" | \"process.parent.macho.go_import_hash\" | \"process.parent.macho.go_imports\" | \"process.parent.macho.go_imports_names_entropy\" | \"process.parent.macho.go_imports_names_var_entropy\" | \"process.parent.macho.go_stripped\" | \"process.parent.macho.import_hash\" | \"process.parent.macho.imports\" | \"process.parent.macho.imports_names_entropy\" | \"process.parent.macho.imports_names_var_entropy\" | \"process.parent.macho.sections\" | \"process.parent.macho.symhash\" | \"process.parent.name\" | \"process.parent.pe.architecture\" | \"process.parent.pe.company\" | \"process.parent.pe.description\" | \"process.parent.pe.file_version\" | \"process.parent.pe.go_import_hash\" | \"process.parent.pe.go_imports\" | \"process.parent.pe.go_imports_names_entropy\" | \"process.parent.pe.go_imports_names_var_entropy\" | \"process.parent.pe.go_stripped\" | \"process.parent.pe.imphash\" | \"process.parent.pe.import_hash\" | \"process.parent.pe.imports\" | \"process.parent.pe.imports_names_entropy\" | \"process.parent.pe.imports_names_var_entropy\" | \"process.parent.pe.original_file_name\" | \"process.parent.pe.pehash\" | \"process.parent.pe.product\" | \"process.parent.pe.sections\" | \"process.parent.pgid\" | \"process.parent.pid\" | \"process.parent.real_group.id\" | \"process.parent.real_group.name\" | \"process.parent.real_user.id\" | \"process.parent.real_user.name\" | \"process.parent.saved_group.id\" | \"process.parent.saved_group.name\" | \"process.parent.saved_user.id\" | \"process.parent.saved_user.name\" | \"process.parent.start\" | \"process.parent.supplemental_groups.id\" | \"process.parent.supplemental_groups.name\" | \"process.parent.thread.capabilities.effective\" | \"process.parent.thread.capabilities.permitted\" | \"process.parent.thread.id\" | \"process.parent.thread.name\" | \"process.parent.title\" | \"process.parent.tty\" | \"process.parent.uptime\" | \"process.parent.user.id\" | \"process.parent.user.name\" | \"process.parent.vpid\" | \"process.parent.working_directory\" | \"process.pe.architecture\" | \"process.pe.company\" | \"process.pe.description\" | \"process.pe.file_version\" | \"process.pe.go_import_hash\" | \"process.pe.go_imports\" | \"process.pe.go_imports_names_entropy\" | \"process.pe.go_imports_names_var_entropy\" | \"process.pe.go_stripped\" | \"process.pe.imphash\" | \"process.pe.import_hash\" | \"process.pe.imports\" | \"process.pe.imports_names_entropy\" | \"process.pe.imports_names_var_entropy\" | \"process.pe.original_file_name\" | \"process.pe.pehash\" | \"process.pe.product\" | \"process.pe.sections\" | \"process.pgid\" | \"process.pid\" | \"process.previous.args\" | \"process.previous.args_count\" | \"process.previous.executable\" | \"process.real_group.id\" | \"process.real_group.name\" | \"process.real_user.id\" | \"process.real_user.name\" | \"process.saved_group.id\" | \"process.saved_group.name\" | \"process.saved_user.id\" | \"process.saved_user.name\" | \"process.session_leader.args\" | \"process.session_leader.args_count\" | \"process.session_leader.command_line\" | \"process.session_leader.entity_id\" | \"process.session_leader.executable\" | \"process.session_leader.group.id\" | \"process.session_leader.group.name\" | \"process.session_leader.interactive\" | \"process.session_leader.name\" | \"process.session_leader.parent.entity_id\" | \"process.session_leader.parent.pid\" | \"process.session_leader.parent.session_leader.entity_id\" | \"process.session_leader.parent.session_leader.pid\" | \"process.session_leader.parent.session_leader.start\" | \"process.session_leader.parent.session_leader.vpid\" | \"process.session_leader.parent.start\" | \"process.session_leader.parent.vpid\" | \"process.session_leader.pid\" | \"process.session_leader.real_group.id\" | \"process.session_leader.real_group.name\" | \"process.session_leader.real_user.id\" | \"process.session_leader.real_user.name\" | \"process.session_leader.same_as_process\" | \"process.session_leader.saved_group.id\" | \"process.session_leader.saved_group.name\" | \"process.session_leader.saved_user.id\" | \"process.session_leader.saved_user.name\" | \"process.session_leader.start\" | \"process.session_leader.supplemental_groups.id\" | \"process.session_leader.supplemental_groups.name\" | \"process.session_leader.tty\" | \"process.session_leader.user.id\" | \"process.session_leader.user.name\" | \"process.session_leader.vpid\" | \"process.session_leader.working_directory\" | \"process.start\" | \"process.supplemental_groups.id\" | \"process.supplemental_groups.name\" | \"process.thread.capabilities.effective\" | \"process.thread.capabilities.permitted\" | \"process.thread.id\" | \"process.thread.name\" | \"process.title\" | \"process.tty\" | \"process.uptime\" | \"process.user.id\" | \"process.user.name\" | \"process.vpid\" | \"process.working_directory\" | \"registry.data.bytes\" | \"registry.data.strings\" | \"registry.data.type\" | \"registry.hive\" | \"registry.key\" | \"registry.path\" | \"registry.value\" | \"related.hash\" | \"related.hosts\" | \"related.ip\" | \"related.user\" | \"rule.author\" | \"rule.category\" | \"rule.description\" | \"rule.id\" | \"rule.license\" | \"rule.name\" | \"rule.reference\" | \"rule.ruleset\" | \"rule.uuid\" | \"rule.version\" | \"server.address\" | \"server.as.number\" | \"server.as.organization.name\" | \"server.bytes\" | \"server.domain\" | \"server.geo.city_name\" | \"server.geo.continent_code\" | \"server.geo.continent_name\" | \"server.geo.country_iso_code\" | \"server.geo.country_name\" | \"server.geo.location\" | \"server.geo.name\" | \"server.geo.postal_code\" | \"server.geo.region_iso_code\" | \"server.geo.region_name\" | \"server.geo.timezone\" | \"server.ip\" | \"server.mac\" | \"server.nat.ip\" | \"server.nat.port\" | \"server.packets\" | \"server.port\" | \"server.registered_domain\" | \"server.subdomain\" | \"server.top_level_domain\" | \"server.user.domain\" | \"server.user.email\" | \"server.user.full_name\" | \"server.user.group.domain\" | \"server.user.group.id\" | \"server.user.group.name\" | \"server.user.hash\" | \"server.user.id\" | \"server.user.name\" | \"server.user.roles\" | \"service.address\" | \"service.ephemeral_id\" | \"service.id\" | \"service.node.name\" | \"service.node.role\" | \"service.node.roles\" | \"service.origin.address\" | \"service.origin.environment\" | \"service.origin.ephemeral_id\" | \"service.origin.id\" | \"service.origin.name\" | \"service.origin.node.name\" | \"service.origin.node.role\" | \"service.origin.node.roles\" | \"service.origin.state\" | \"service.origin.type\" | \"service.origin.version\" | \"service.state\" | \"service.target.address\" | \"service.target.environment\" | \"service.target.ephemeral_id\" | \"service.target.id\" | \"service.target.name\" | \"service.target.node.name\" | \"service.target.node.role\" | \"service.target.node.roles\" | \"service.target.state\" | \"service.target.type\" | \"service.target.version\" | \"service.type\" | \"service.version\" | \"source.address\" | \"source.as.number\" | \"source.as.organization.name\" | \"source.bytes\" | \"source.domain\" | \"source.geo.city_name\" | \"source.geo.continent_code\" | \"source.geo.continent_name\" | \"source.geo.country_iso_code\" | \"source.geo.country_name\" | \"source.geo.location\" | \"source.geo.name\" | \"source.geo.postal_code\" | \"source.geo.region_iso_code\" | \"source.geo.region_name\" | \"source.geo.timezone\" | \"source.ip\" | \"source.mac\" | \"source.nat.ip\" | \"source.nat.port\" | \"source.packets\" | \"source.port\" | \"source.registered_domain\" | \"source.subdomain\" | \"source.top_level_domain\" | \"source.user.domain\" | \"source.user.email\" | \"source.user.full_name\" | \"source.user.group.domain\" | \"source.user.group.id\" | \"source.user.group.name\" | \"source.user.hash\" | \"source.user.id\" | \"source.user.name\" | \"source.user.roles\" | \"span.id\" | \"threat.enrichments\" | \"threat.feed.dashboard_id\" | \"threat.feed.description\" | \"threat.feed.name\" | \"threat.feed.reference\" | \"threat.framework\" | \"threat.group.alias\" | \"threat.group.id\" | \"threat.group.name\" | \"threat.group.reference\" | \"threat.indicator.as.number\" | \"threat.indicator.as.organization.name\" | \"threat.indicator.confidence\" | \"threat.indicator.description\" | \"threat.indicator.email.address\" | \"threat.indicator.file.accessed\" | \"threat.indicator.file.attributes\" | \"threat.indicator.file.code_signature.digest_algorithm\" | \"threat.indicator.file.code_signature.exists\" | \"threat.indicator.file.code_signature.signing_id\" | \"threat.indicator.file.code_signature.status\" | \"threat.indicator.file.code_signature.subject_name\" | \"threat.indicator.file.code_signature.team_id\" | \"threat.indicator.file.code_signature.timestamp\" | \"threat.indicator.file.code_signature.trusted\" | \"threat.indicator.file.code_signature.valid\" | \"threat.indicator.file.created\" | \"threat.indicator.file.ctime\" | \"threat.indicator.file.device\" | \"threat.indicator.file.directory\" | \"threat.indicator.file.drive_letter\" | \"threat.indicator.file.elf.architecture\" | \"threat.indicator.file.elf.byte_order\" | \"threat.indicator.file.elf.cpu_type\" | \"threat.indicator.file.elf.creation_date\" | \"threat.indicator.file.elf.exports\" | \"threat.indicator.file.elf.go_import_hash\" | \"threat.indicator.file.elf.go_imports\" | \"threat.indicator.file.elf.go_imports_names_entropy\" | \"threat.indicator.file.elf.go_imports_names_var_entropy\" | \"threat.indicator.file.elf.go_stripped\" | \"threat.indicator.file.elf.header.abi_version\" | \"threat.indicator.file.elf.header.class\" | \"threat.indicator.file.elf.header.data\" | \"threat.indicator.file.elf.header.entrypoint\" | \"threat.indicator.file.elf.header.object_version\" | \"threat.indicator.file.elf.header.os_abi\" | \"threat.indicator.file.elf.header.type\" | \"threat.indicator.file.elf.header.version\" | \"threat.indicator.file.elf.import_hash\" | \"threat.indicator.file.elf.imports\" | \"threat.indicator.file.elf.imports_names_entropy\" | \"threat.indicator.file.elf.imports_names_var_entropy\" | \"threat.indicator.file.elf.sections\" | \"threat.indicator.file.elf.segments\" | \"threat.indicator.file.elf.shared_libraries\" | \"threat.indicator.file.elf.telfhash\" | \"threat.indicator.file.extension\" | \"threat.indicator.file.fork_name\" | \"threat.indicator.file.gid\" | \"threat.indicator.file.group\" | \"threat.indicator.file.hash.md5\" | \"threat.indicator.file.hash.sha1\" | \"threat.indicator.file.hash.sha256\" | \"threat.indicator.file.hash.sha384\" | \"threat.indicator.file.hash.sha512\" | \"threat.indicator.file.hash.ssdeep\" | \"threat.indicator.file.hash.tlsh\" | \"threat.indicator.file.inode\" | \"threat.indicator.file.mime_type\" | \"threat.indicator.file.mode\" | \"threat.indicator.file.mtime\" | \"threat.indicator.file.name\" | \"threat.indicator.file.owner\" | \"threat.indicator.file.path\" | \"threat.indicator.file.pe.architecture\" | \"threat.indicator.file.pe.company\" | \"threat.indicator.file.pe.description\" | \"threat.indicator.file.pe.file_version\" | \"threat.indicator.file.pe.go_import_hash\" | \"threat.indicator.file.pe.go_imports\" | \"threat.indicator.file.pe.go_imports_names_entropy\" | \"threat.indicator.file.pe.go_imports_names_var_entropy\" | \"threat.indicator.file.pe.go_stripped\" | \"threat.indicator.file.pe.imphash\" | \"threat.indicator.file.pe.import_hash\" | \"threat.indicator.file.pe.imports\" | \"threat.indicator.file.pe.imports_names_entropy\" | \"threat.indicator.file.pe.imports_names_var_entropy\" | \"threat.indicator.file.pe.original_file_name\" | \"threat.indicator.file.pe.pehash\" | \"threat.indicator.file.pe.product\" | \"threat.indicator.file.pe.sections\" | \"threat.indicator.file.size\" | \"threat.indicator.file.target_path\" | \"threat.indicator.file.type\" | \"threat.indicator.file.uid\" | \"threat.indicator.file.x509.alternative_names\" | \"threat.indicator.file.x509.issuer.common_name\" | \"threat.indicator.file.x509.issuer.country\" | \"threat.indicator.file.x509.issuer.distinguished_name\" | \"threat.indicator.file.x509.issuer.locality\" | \"threat.indicator.file.x509.issuer.organization\" | \"threat.indicator.file.x509.issuer.organizational_unit\" | \"threat.indicator.file.x509.issuer.state_or_province\" | \"threat.indicator.file.x509.not_after\" | \"threat.indicator.file.x509.not_before\" | \"threat.indicator.file.x509.public_key_algorithm\" | \"threat.indicator.file.x509.public_key_curve\" | \"threat.indicator.file.x509.public_key_exponent\" | \"threat.indicator.file.x509.public_key_size\" | \"threat.indicator.file.x509.serial_number\" | \"threat.indicator.file.x509.signature_algorithm\" | \"threat.indicator.file.x509.subject.common_name\" | \"threat.indicator.file.x509.subject.country\" | \"threat.indicator.file.x509.subject.distinguished_name\" | \"threat.indicator.file.x509.subject.locality\" | \"threat.indicator.file.x509.subject.organization\" | \"threat.indicator.file.x509.subject.organizational_unit\" | \"threat.indicator.file.x509.subject.state_or_province\" | \"threat.indicator.file.x509.version_number\" | \"threat.indicator.first_seen\" | \"threat.indicator.geo.city_name\" | \"threat.indicator.geo.continent_code\" | \"threat.indicator.geo.continent_name\" | \"threat.indicator.geo.country_iso_code\" | \"threat.indicator.geo.country_name\" | \"threat.indicator.geo.location\" | \"threat.indicator.geo.name\" | \"threat.indicator.geo.postal_code\" | \"threat.indicator.geo.region_iso_code\" | \"threat.indicator.geo.region_name\" | \"threat.indicator.geo.timezone\" | \"threat.indicator.ip\" | \"threat.indicator.last_seen\" | \"threat.indicator.marking.tlp\" | \"threat.indicator.marking.tlp_version\" | \"threat.indicator.modified_at\" | \"threat.indicator.name\" | \"threat.indicator.port\" | \"threat.indicator.provider\" | \"threat.indicator.reference\" | \"threat.indicator.registry.data.bytes\" | \"threat.indicator.registry.data.strings\" | \"threat.indicator.registry.data.type\" | \"threat.indicator.registry.hive\" | \"threat.indicator.registry.key\" | \"threat.indicator.registry.path\" | \"threat.indicator.registry.value\" | \"threat.indicator.scanner_stats\" | \"threat.indicator.sightings\" | \"threat.indicator.type\" | \"threat.indicator.url.domain\" | \"threat.indicator.url.extension\" | \"threat.indicator.url.fragment\" | \"threat.indicator.url.full\" | \"threat.indicator.url.original\" | \"threat.indicator.url.password\" | \"threat.indicator.url.path\" | \"threat.indicator.url.port\" | \"threat.indicator.url.query\" | \"threat.indicator.url.registered_domain\" | \"threat.indicator.url.scheme\" | \"threat.indicator.url.subdomain\" | \"threat.indicator.url.top_level_domain\" | \"threat.indicator.url.username\" | \"threat.indicator.x509.alternative_names\" | \"threat.indicator.x509.issuer.common_name\" | \"threat.indicator.x509.issuer.country\" | \"threat.indicator.x509.issuer.distinguished_name\" | \"threat.indicator.x509.issuer.locality\" | \"threat.indicator.x509.issuer.organization\" | \"threat.indicator.x509.issuer.organizational_unit\" | \"threat.indicator.x509.issuer.state_or_province\" | \"threat.indicator.x509.not_after\" | \"threat.indicator.x509.not_before\" | \"threat.indicator.x509.public_key_algorithm\" | \"threat.indicator.x509.public_key_curve\" | \"threat.indicator.x509.public_key_exponent\" | \"threat.indicator.x509.public_key_size\" | \"threat.indicator.x509.serial_number\" | \"threat.indicator.x509.signature_algorithm\" | \"threat.indicator.x509.subject.common_name\" | \"threat.indicator.x509.subject.country\" | \"threat.indicator.x509.subject.distinguished_name\" | \"threat.indicator.x509.subject.locality\" | \"threat.indicator.x509.subject.organization\" | \"threat.indicator.x509.subject.organizational_unit\" | \"threat.indicator.x509.subject.state_or_province\" | \"threat.indicator.x509.version_number\" | \"threat.software.alias\" | \"threat.software.id\" | \"threat.software.name\" | \"threat.software.platforms\" | \"threat.software.reference\" | \"threat.software.type\" | \"threat.tactic.id\" | \"threat.tactic.name\" | \"threat.tactic.reference\" | \"threat.technique.id\" | \"threat.technique.name\" | \"threat.technique.reference\" | \"threat.technique.subtechnique.id\" | \"threat.technique.subtechnique.name\" | \"threat.technique.subtechnique.reference\" | \"tls.cipher\" | \"tls.client.certificate\" | \"tls.client.certificate_chain\" | \"tls.client.hash.md5\" | \"tls.client.hash.sha1\" | \"tls.client.hash.sha256\" | \"tls.client.issuer\" | \"tls.client.ja3\" | \"tls.client.not_after\" | \"tls.client.not_before\" | \"tls.client.server_name\" | \"tls.client.subject\" | \"tls.client.supported_ciphers\" | \"tls.client.x509.alternative_names\" | \"tls.client.x509.issuer.common_name\" | \"tls.client.x509.issuer.country\" | \"tls.client.x509.issuer.distinguished_name\" | \"tls.client.x509.issuer.locality\" | \"tls.client.x509.issuer.organization\" | \"tls.client.x509.issuer.organizational_unit\" | \"tls.client.x509.issuer.state_or_province\" | \"tls.client.x509.not_after\" | \"tls.client.x509.not_before\" | \"tls.client.x509.public_key_algorithm\" | \"tls.client.x509.public_key_curve\" | \"tls.client.x509.public_key_exponent\" | \"tls.client.x509.public_key_size\" | \"tls.client.x509.serial_number\" | \"tls.client.x509.signature_algorithm\" | \"tls.client.x509.subject.common_name\" | \"tls.client.x509.subject.country\" | \"tls.client.x509.subject.distinguished_name\" | \"tls.client.x509.subject.locality\" | \"tls.client.x509.subject.organization\" | \"tls.client.x509.subject.organizational_unit\" | \"tls.client.x509.subject.state_or_province\" | \"tls.client.x509.version_number\" | \"tls.curve\" | \"tls.established\" | \"tls.next_protocol\" | \"tls.resumed\" | \"tls.server.certificate\" | \"tls.server.certificate_chain\" | \"tls.server.hash.md5\" | \"tls.server.hash.sha1\" | \"tls.server.hash.sha256\" | \"tls.server.issuer\" | \"tls.server.ja3s\" | \"tls.server.not_after\" | \"tls.server.not_before\" | \"tls.server.subject\" | \"tls.server.x509.alternative_names\" | \"tls.server.x509.issuer.common_name\" | \"tls.server.x509.issuer.country\" | \"tls.server.x509.issuer.distinguished_name\" | \"tls.server.x509.issuer.locality\" | \"tls.server.x509.issuer.organization\" | \"tls.server.x509.issuer.organizational_unit\" | \"tls.server.x509.issuer.state_or_province\" | \"tls.server.x509.not_after\" | \"tls.server.x509.not_before\" | \"tls.server.x509.public_key_algorithm\" | \"tls.server.x509.public_key_curve\" | \"tls.server.x509.public_key_exponent\" | \"tls.server.x509.public_key_size\" | \"tls.server.x509.serial_number\" | \"tls.server.x509.signature_algorithm\" | \"tls.server.x509.subject.common_name\" | \"tls.server.x509.subject.country\" | \"tls.server.x509.subject.distinguished_name\" | \"tls.server.x509.subject.locality\" | \"tls.server.x509.subject.organization\" | \"tls.server.x509.subject.organizational_unit\" | \"tls.server.x509.subject.state_or_province\" | \"tls.server.x509.version_number\" | \"tls.version\" | \"tls.version_protocol\" | \"trace.id\" | \"transaction.id\" | \"url.domain\" | \"url.extension\" | \"url.fragment\" | \"url.full\" | \"url.original\" | \"url.password\" | \"url.path\" | \"url.port\" | \"url.query\" | \"url.registered_domain\" | \"url.scheme\" | \"url.subdomain\" | \"url.top_level_domain\" | \"url.username\" | \"user.changes.domain\" | \"user.changes.email\" | \"user.changes.full_name\" | \"user.changes.group.domain\" | \"user.changes.group.id\" | \"user.changes.group.name\" | \"user.changes.hash\" | \"user.changes.id\" | \"user.changes.name\" | \"user.changes.roles\" | \"user.domain\" | \"user.effective.domain\" | \"user.effective.email\" | \"user.effective.full_name\" | \"user.effective.group.domain\" | \"user.effective.group.id\" | \"user.effective.group.name\" | \"user.effective.hash\" | \"user.effective.id\" | \"user.effective.name\" | \"user.effective.roles\" | \"user.email\" | \"user.full_name\" | \"user.group.domain\" | \"user.group.id\" | \"user.group.name\" | \"user.hash\" | \"user.id\" | \"user.name\" | \"user.risk.calculated_level\" | \"user.risk.calculated_score\" | \"user.risk.calculated_score_norm\" | \"user.risk.static_level\" | \"user.risk.static_score\" | \"user.risk.static_score_norm\" | \"user.roles\" | \"user.target.domain\" | \"user.target.email\" | \"user.target.full_name\" | \"user.target.group.domain\" | \"user.target.group.id\" | \"user.target.group.name\" | \"user.target.hash\" | \"user.target.id\" | \"user.target.name\" | \"user.target.roles\" | \"user_agent.device.name\" | \"user_agent.name\" | \"user_agent.original\" | \"user_agent.os.family\" | \"user_agent.os.full\" | \"user_agent.os.kernel\" | \"user_agent.os.name\" | \"user_agent.os.platform\" | \"user_agent.os.type\" | \"user_agent.os.version\" | \"user_agent.version\" | \"vulnerability.category\" | \"vulnerability.classification\" | \"vulnerability.description\" | \"vulnerability.enumeration\" | \"vulnerability.id\" | \"vulnerability.reference\" | \"vulnerability.report_id\" | \"vulnerability.scanner.vendor\" | \"vulnerability.score.base\" | \"vulnerability.score.environmental\" | \"vulnerability.score.temporal\" | \"vulnerability.score.version\" | \"vulnerability.severity\" | \"_id\" | \"_source\" | \"_index\" | \"_ignored\" | \"_routing\" | ", + { + "pluginId": "fieldsMetadata", + "scope": "common", + "docId": "kibFieldsMetadataPluginApi", + "section": "def-common.AnyFieldName", + "text": "AnyFieldName" + }, + " | \"data_stream.dataset\" | \"data_stream.namespace\" | \"data_stream.type\" | \"dll.pe.sections.entropy\" | \"dll.pe.sections.name\" | \"dll.pe.sections.physical_size\" | \"dll.pe.sections.var_entropy\" | \"dll.pe.sections.virtual_size\" | \"dns.answers.class\" | \"dns.answers.data\" | \"dns.answers.name\" | \"dns.answers.ttl\" | \"dns.answers.type\" | \"email.attachments.file.extension\" | \"email.attachments.file.hash.md5\" | \"email.attachments.file.hash.sha1\" | \"email.attachments.file.hash.sha256\" | \"email.attachments.file.hash.sha384\" | \"email.attachments.file.hash.sha512\" | \"email.attachments.file.hash.ssdeep\" | \"email.attachments.file.hash.tlsh\" | \"email.attachments.file.mime_type\" | \"email.attachments.file.name\" | \"email.attachments.file.size\" | \"faas.trigger.request_id\" | \"faas.trigger.type\" | \"file.elf.sections.chi2\" | \"file.elf.sections.entropy\" | \"file.elf.sections.flags\" | \"file.elf.sections.name\" | \"file.elf.sections.physical_offset\" | \"file.elf.sections.physical_size\" | \"file.elf.sections.type\" | \"file.elf.sections.var_entropy\" | \"file.elf.sections.virtual_address\" | \"file.elf.sections.virtual_size\" | \"file.elf.segments.sections\" | \"file.elf.segments.type\" | \"file.macho.sections.entropy\" | \"file.macho.sections.name\" | \"file.macho.sections.physical_size\" | \"file.macho.sections.var_entropy\" | \"file.macho.sections.virtual_size\" | \"file.pe.sections.entropy\" | \"file.pe.sections.name\" | \"file.pe.sections.physical_size\" | \"file.pe.sections.var_entropy\" | \"file.pe.sections.virtual_size\" | \"log.syslog.appname\" | \"log.syslog.facility.code\" | \"log.syslog.facility.name\" | \"log.syslog.hostname\" | \"log.syslog.msgid\" | \"log.syslog.priority\" | \"log.syslog.procid\" | \"log.syslog.severity.code\" | \"log.syslog.severity.name\" | \"log.syslog.structured_data\" | \"log.syslog.version\" | \"network.inner.vlan.id\" | \"network.inner.vlan.name\" | \"observer.egress.interface.alias\" | \"observer.egress.interface.id\" | \"observer.egress.interface.name\" | \"observer.egress.vlan.id\" | \"observer.egress.vlan.name\" | \"observer.egress.zone\" | \"observer.ingress.interface.alias\" | \"observer.ingress.interface.id\" | \"observer.ingress.interface.name\" | \"observer.ingress.vlan.id\" | \"observer.ingress.vlan.name\" | \"observer.ingress.zone\" | \"process.elf.sections.chi2\" | \"process.elf.sections.entropy\" | \"process.elf.sections.flags\" | \"process.elf.sections.name\" | \"process.elf.sections.physical_offset\" | \"process.elf.sections.physical_size\" | \"process.elf.sections.type\" | \"process.elf.sections.var_entropy\" | \"process.elf.sections.virtual_address\" | \"process.elf.sections.virtual_size\" | \"process.elf.segments.sections\" | \"process.elf.segments.type\" | \"process.entry_leader.tty.char_device.major\" | \"process.entry_leader.tty.char_device.minor\" | \"process.group_leader.tty.char_device.major\" | \"process.group_leader.tty.char_device.minor\" | \"process.io.bytes_skipped\" | \"process.io.bytes_skipped.length\" | \"process.io.bytes_skipped.offset\" | \"process.io.max_bytes_per_process_exceeded\" | \"process.io.text\" | \"process.io.total_bytes_captured\" | \"process.io.total_bytes_skipped\" | \"process.io.type\" | \"process.macho.sections.entropy\" | \"process.macho.sections.name\" | \"process.macho.sections.physical_size\" | \"process.macho.sections.var_entropy\" | \"process.macho.sections.virtual_size\" | \"process.parent.elf.sections.chi2\" | \"process.parent.elf.sections.entropy\" | \"process.parent.elf.sections.flags\" | \"process.parent.elf.sections.name\" | \"process.parent.elf.sections.physical_offset\" | \"process.parent.elf.sections.physical_size\" | \"process.parent.elf.sections.type\" | \"process.parent.elf.sections.var_entropy\" | \"process.parent.elf.sections.virtual_address\" | \"process.parent.elf.sections.virtual_size\" | \"process.parent.elf.segments.sections\" | \"process.parent.elf.segments.type\" | \"process.parent.macho.sections.entropy\" | \"process.parent.macho.sections.name\" | \"process.parent.macho.sections.physical_size\" | \"process.parent.macho.sections.var_entropy\" | \"process.parent.macho.sections.virtual_size\" | \"process.parent.pe.sections.entropy\" | \"process.parent.pe.sections.name\" | \"process.parent.pe.sections.physical_size\" | \"process.parent.pe.sections.var_entropy\" | \"process.parent.pe.sections.virtual_size\" | \"process.parent.tty.char_device.major\" | \"process.parent.tty.char_device.minor\" | \"process.pe.sections.entropy\" | \"process.pe.sections.name\" | \"process.pe.sections.physical_size\" | \"process.pe.sections.var_entropy\" | \"process.pe.sections.virtual_size\" | \"process.session_leader.tty.char_device.major\" | \"process.session_leader.tty.char_device.minor\" | \"process.tty.char_device.major\" | \"process.tty.char_device.minor\" | \"process.tty.columns\" | \"process.tty.rows\" | \"threat.enrichments.indicator\" | \"threat.enrichments.indicator.as.number\" | \"threat.enrichments.indicator.as.organization.name\" | \"threat.enrichments.indicator.confidence\" | \"threat.enrichments.indicator.description\" | \"threat.enrichments.indicator.email.address\" | \"threat.enrichments.indicator.file.accessed\" | \"threat.enrichments.indicator.file.attributes\" | \"threat.enrichments.indicator.file.code_signature.digest_algorithm\" | \"threat.enrichments.indicator.file.code_signature.exists\" | \"threat.enrichments.indicator.file.code_signature.signing_id\" | \"threat.enrichments.indicator.file.code_signature.status\" | \"threat.enrichments.indicator.file.code_signature.subject_name\" | \"threat.enrichments.indicator.file.code_signature.team_id\" | \"threat.enrichments.indicator.file.code_signature.timestamp\" | \"threat.enrichments.indicator.file.code_signature.trusted\" | \"threat.enrichments.indicator.file.code_signature.valid\" | \"threat.enrichments.indicator.file.created\" | \"threat.enrichments.indicator.file.ctime\" | \"threat.enrichments.indicator.file.device\" | \"threat.enrichments.indicator.file.directory\" | \"threat.enrichments.indicator.file.drive_letter\" | \"threat.enrichments.indicator.file.elf.architecture\" | \"threat.enrichments.indicator.file.elf.byte_order\" | \"threat.enrichments.indicator.file.elf.cpu_type\" | \"threat.enrichments.indicator.file.elf.creation_date\" | \"threat.enrichments.indicator.file.elf.exports\" | \"threat.enrichments.indicator.file.elf.go_import_hash\" | \"threat.enrichments.indicator.file.elf.go_imports\" | \"threat.enrichments.indicator.file.elf.go_imports_names_entropy\" | \"threat.enrichments.indicator.file.elf.go_imports_names_var_entropy\" | \"threat.enrichments.indicator.file.elf.go_stripped\" | \"threat.enrichments.indicator.file.elf.header.abi_version\" | \"threat.enrichments.indicator.file.elf.header.class\" | \"threat.enrichments.indicator.file.elf.header.data\" | \"threat.enrichments.indicator.file.elf.header.entrypoint\" | \"threat.enrichments.indicator.file.elf.header.object_version\" | \"threat.enrichments.indicator.file.elf.header.os_abi\" | \"threat.enrichments.indicator.file.elf.header.type\" | \"threat.enrichments.indicator.file.elf.header.version\" | \"threat.enrichments.indicator.file.elf.import_hash\" | \"threat.enrichments.indicator.file.elf.imports\" | \"threat.enrichments.indicator.file.elf.imports_names_entropy\" | \"threat.enrichments.indicator.file.elf.imports_names_var_entropy\" | \"threat.enrichments.indicator.file.elf.sections\" | \"threat.enrichments.indicator.file.elf.sections.chi2\" | \"threat.enrichments.indicator.file.elf.sections.entropy\" | \"threat.enrichments.indicator.file.elf.sections.flags\" | \"threat.enrichments.indicator.file.elf.sections.name\" | \"threat.enrichments.indicator.file.elf.sections.physical_offset\" | \"threat.enrichments.indicator.file.elf.sections.physical_size\" | \"threat.enrichments.indicator.file.elf.sections.type\" | \"threat.enrichments.indicator.file.elf.sections.var_entropy\" | \"threat.enrichments.indicator.file.elf.sections.virtual_address\" | \"threat.enrichments.indicator.file.elf.sections.virtual_size\" | \"threat.enrichments.indicator.file.elf.segments\" | \"threat.enrichments.indicator.file.elf.segments.sections\" | \"threat.enrichments.indicator.file.elf.segments.type\" | \"threat.enrichments.indicator.file.elf.shared_libraries\" | \"threat.enrichments.indicator.file.elf.telfhash\" | \"threat.enrichments.indicator.file.extension\" | \"threat.enrichments.indicator.file.fork_name\" | \"threat.enrichments.indicator.file.gid\" | \"threat.enrichments.indicator.file.group\" | \"threat.enrichments.indicator.file.hash.md5\" | \"threat.enrichments.indicator.file.hash.sha1\" | \"threat.enrichments.indicator.file.hash.sha256\" | \"threat.enrichments.indicator.file.hash.sha384\" | \"threat.enrichments.indicator.file.hash.sha512\" | \"threat.enrichments.indicator.file.hash.ssdeep\" | \"threat.enrichments.indicator.file.hash.tlsh\" | \"threat.enrichments.indicator.file.inode\" | \"threat.enrichments.indicator.file.mime_type\" | \"threat.enrichments.indicator.file.mode\" | \"threat.enrichments.indicator.file.mtime\" | \"threat.enrichments.indicator.file.name\" | \"threat.enrichments.indicator.file.owner\" | \"threat.enrichments.indicator.file.path\" | \"threat.enrichments.indicator.file.pe.architecture\" | \"threat.enrichments.indicator.file.pe.company\" | \"threat.enrichments.indicator.file.pe.description\" | \"threat.enrichments.indicator.file.pe.file_version\" | \"threat.enrichments.indicator.file.pe.go_import_hash\" | \"threat.enrichments.indicator.file.pe.go_imports\" | \"threat.enrichments.indicator.file.pe.go_imports_names_entropy\" | \"threat.enrichments.indicator.file.pe.go_imports_names_var_entropy\" | \"threat.enrichments.indicator.file.pe.go_stripped\" | \"threat.enrichments.indicator.file.pe.imphash\" | \"threat.enrichments.indicator.file.pe.import_hash\" | \"threat.enrichments.indicator.file.pe.imports\" | \"threat.enrichments.indicator.file.pe.imports_names_entropy\" | \"threat.enrichments.indicator.file.pe.imports_names_var_entropy\" | \"threat.enrichments.indicator.file.pe.original_file_name\" | \"threat.enrichments.indicator.file.pe.pehash\" | \"threat.enrichments.indicator.file.pe.product\" | \"threat.enrichments.indicator.file.pe.sections\" | \"threat.enrichments.indicator.file.pe.sections.entropy\" | \"threat.enrichments.indicator.file.pe.sections.name\" | \"threat.enrichments.indicator.file.pe.sections.physical_size\" | \"threat.enrichments.indicator.file.pe.sections.var_entropy\" | \"threat.enrichments.indicator.file.pe.sections.virtual_size\" | \"threat.enrichments.indicator.file.size\" | \"threat.enrichments.indicator.file.target_path\" | \"threat.enrichments.indicator.file.type\" | \"threat.enrichments.indicator.file.uid\" | \"threat.enrichments.indicator.file.x509.alternative_names\" | \"threat.enrichments.indicator.file.x509.issuer.common_name\" | \"threat.enrichments.indicator.file.x509.issuer.country\" | \"threat.enrichments.indicator.file.x509.issuer.distinguished_name\" | \"threat.enrichments.indicator.file.x509.issuer.locality\" | \"threat.enrichments.indicator.file.x509.issuer.organization\" | \"threat.enrichments.indicator.file.x509.issuer.organizational_unit\" | \"threat.enrichments.indicator.file.x509.issuer.state_or_province\" | \"threat.enrichments.indicator.file.x509.not_after\" | \"threat.enrichments.indicator.file.x509.not_before\" | \"threat.enrichments.indicator.file.x509.public_key_algorithm\" | \"threat.enrichments.indicator.file.x509.public_key_curve\" | \"threat.enrichments.indicator.file.x509.public_key_exponent\" | \"threat.enrichments.indicator.file.x509.public_key_size\" | \"threat.enrichments.indicator.file.x509.serial_number\" | \"threat.enrichments.indicator.file.x509.signature_algorithm\" | \"threat.enrichments.indicator.file.x509.subject.common_name\" | \"threat.enrichments.indicator.file.x509.subject.country\" | \"threat.enrichments.indicator.file.x509.subject.distinguished_name\" | \"threat.enrichments.indicator.file.x509.subject.locality\" | \"threat.enrichments.indicator.file.x509.subject.organization\" | \"threat.enrichments.indicator.file.x509.subject.organizational_unit\" | \"threat.enrichments.indicator.file.x509.subject.state_or_province\" | \"threat.enrichments.indicator.file.x509.version_number\" | \"threat.enrichments.indicator.first_seen\" | \"threat.enrichments.indicator.geo.city_name\" | \"threat.enrichments.indicator.geo.continent_code\" | \"threat.enrichments.indicator.geo.continent_name\" | \"threat.enrichments.indicator.geo.country_iso_code\" | \"threat.enrichments.indicator.geo.country_name\" | \"threat.enrichments.indicator.geo.location\" | \"threat.enrichments.indicator.geo.name\" | \"threat.enrichments.indicator.geo.postal_code\" | \"threat.enrichments.indicator.geo.region_iso_code\" | \"threat.enrichments.indicator.geo.region_name\" | \"threat.enrichments.indicator.geo.timezone\" | \"threat.enrichments.indicator.ip\" | \"threat.enrichments.indicator.last_seen\" | \"threat.enrichments.indicator.marking.tlp\" | \"threat.enrichments.indicator.marking.tlp_version\" | \"threat.enrichments.indicator.modified_at\" | \"threat.enrichments.indicator.name\" | \"threat.enrichments.indicator.port\" | \"threat.enrichments.indicator.provider\" | \"threat.enrichments.indicator.reference\" | \"threat.enrichments.indicator.registry.data.bytes\" | \"threat.enrichments.indicator.registry.data.strings\" | \"threat.enrichments.indicator.registry.data.type\" | \"threat.enrichments.indicator.registry.hive\" | \"threat.enrichments.indicator.registry.key\" | \"threat.enrichments.indicator.registry.path\" | \"threat.enrichments.indicator.registry.value\" | \"threat.enrichments.indicator.scanner_stats\" | \"threat.enrichments.indicator.sightings\" | \"threat.enrichments.indicator.type\" | \"threat.enrichments.indicator.url.domain\" | \"threat.enrichments.indicator.url.extension\" | \"threat.enrichments.indicator.url.fragment\" | \"threat.enrichments.indicator.url.full\" | \"threat.enrichments.indicator.url.original\" | \"threat.enrichments.indicator.url.password\" | \"threat.enrichments.indicator.url.path\" | \"threat.enrichments.indicator.url.port\" | \"threat.enrichments.indicator.url.query\" | \"threat.enrichments.indicator.url.registered_domain\" | \"threat.enrichments.indicator.url.scheme\" | \"threat.enrichments.indicator.url.subdomain\" | \"threat.enrichments.indicator.url.top_level_domain\" | \"threat.enrichments.indicator.url.username\" | \"threat.enrichments.indicator.x509.alternative_names\" | \"threat.enrichments.indicator.x509.issuer.common_name\" | \"threat.enrichments.indicator.x509.issuer.country\" | \"threat.enrichments.indicator.x509.issuer.distinguished_name\" | \"threat.enrichments.indicator.x509.issuer.locality\" | \"threat.enrichments.indicator.x509.issuer.organization\" | \"threat.enrichments.indicator.x509.issuer.organizational_unit\" | \"threat.enrichments.indicator.x509.issuer.state_or_province\" | \"threat.enrichments.indicator.x509.not_after\" | \"threat.enrichments.indicator.x509.not_before\" | \"threat.enrichments.indicator.x509.public_key_algorithm\" | \"threat.enrichments.indicator.x509.public_key_curve\" | \"threat.enrichments.indicator.x509.public_key_exponent\" | \"threat.enrichments.indicator.x509.public_key_size\" | \"threat.enrichments.indicator.x509.serial_number\" | \"threat.enrichments.indicator.x509.signature_algorithm\" | \"threat.enrichments.indicator.x509.subject.common_name\" | \"threat.enrichments.indicator.x509.subject.country\" | \"threat.enrichments.indicator.x509.subject.distinguished_name\" | \"threat.enrichments.indicator.x509.subject.locality\" | \"threat.enrichments.indicator.x509.subject.organization\" | \"threat.enrichments.indicator.x509.subject.organizational_unit\" | \"threat.enrichments.indicator.x509.subject.state_or_province\" | \"threat.enrichments.indicator.x509.version_number\" | \"threat.enrichments.matched.atomic\" | \"threat.enrichments.matched.field\" | \"threat.enrichments.matched.id\" | \"threat.enrichments.matched.index\" | \"threat.enrichments.matched.occurred\" | \"threat.enrichments.matched.type\" | \"threat.indicator.file.elf.sections.chi2\" | \"threat.indicator.file.elf.sections.entropy\" | \"threat.indicator.file.elf.sections.flags\" | \"threat.indicator.file.elf.sections.name\" | \"threat.indicator.file.elf.sections.physical_offset\" | \"threat.indicator.file.elf.sections.physical_size\" | \"threat.indicator.file.elf.sections.type\" | \"threat.indicator.file.elf.sections.var_entropy\" | \"threat.indicator.file.elf.sections.virtual_address\" | \"threat.indicator.file.elf.sections.virtual_size\" | \"threat.indicator.file.elf.segments.sections\" | \"threat.indicator.file.elf.segments.type\" | \"threat.indicator.file.pe.sections.entropy\" | \"threat.indicator.file.pe.sections.name\" | \"threat.indicator.file.pe.sections.physical_size\" | \"threat.indicator.file.pe.sections.var_entropy\" | \"threat.indicator.file.pe.sections.virtual_size\" | \"_size\" | \"_doc_count\" | \"_field_names\" | \"_meta\" | \"_tier\"" ], "path": "x-pack/plugins/fields_metadata/common/fields_metadata/types.ts", "deprecated": false, @@ -618,7 +658,7 @@ "label": "IntegrationFieldName", "description": [], "signature": [ - "string" + "string & {}" ], "path": "x-pack/plugins/fields_metadata/common/fields_metadata/types.ts", "deprecated": false, @@ -633,7 +673,7 @@ "label": "PartialFieldMetadataPlain", "description": [], "signature": [ - "{ name?: string | undefined; } & { allowed_values?: ({ description: string; name: string; } & { expected_event_types?: string[] | undefined; beta?: string | undefined; })[] | undefined; beta?: string | undefined; dashed_name?: string | undefined; description?: string | undefined; doc_values?: boolean | undefined; example?: unknown; expected_values?: string[] | undefined; flat_name?: string | undefined; format?: string | undefined; ignore_above?: number | undefined; index?: boolean | undefined; input_format?: string | undefined; level?: string | undefined; multi_fields?: { flat_name: string; name: string; type: string; }[] | undefined; normalize?: string[] | undefined; object_type?: string | undefined; original_fieldset?: string | undefined; output_format?: string | undefined; output_precision?: number | undefined; pattern?: string | undefined; required?: boolean | undefined; scaling_factor?: number | undefined; short?: string | undefined; source?: \"unknown\" | \"ecs\" | \"integration\" | undefined; type?: string | undefined; }" + "{ name?: string | undefined; } & { allowed_values?: ({ description: string; name: string; } & { expected_event_types?: string[] | undefined; beta?: string | undefined; })[] | undefined; beta?: string | undefined; dashed_name?: string | undefined; description?: string | undefined; doc_values?: boolean | undefined; example?: unknown; expected_values?: string[] | undefined; flat_name?: string | undefined; format?: string | undefined; ignore_above?: number | undefined; index?: boolean | undefined; input_format?: string | undefined; level?: string | undefined; multi_fields?: { flat_name: string; name: string; type: string; }[] | undefined; normalize?: string[] | undefined; object_type?: string | undefined; original_fieldset?: string | undefined; output_format?: string | undefined; output_precision?: number | undefined; pattern?: string | undefined; required?: boolean | undefined; scaling_factor?: number | undefined; short?: string | undefined; source?: \"unknown\" | \"ecs\" | \"integration\" | \"metadata\" | undefined; type?: string | undefined; documentation_url?: string | undefined; }" ], "path": "x-pack/plugins/fields_metadata/common/fields_metadata/types.ts", "deprecated": false, @@ -654,6 +694,21 @@ "deprecated": false, "trackAdoption": false, "initialIsOpen": false + }, + { + "parentPluginId": "fieldsMetadata", + "id": "def-common.TMetadataFields", + "type": "Type", + "tags": [], + "label": "TMetadataFields", + "description": [], + "signature": [ + "{ _index: { dashed_name: string; description: string; example: string; flat_name: string; name: string; short: string; type: string; documentation_url: string; }; _id: { dashed_name: string; description: string; example: string; flat_name: string; name: string; short: string; type: string; documentation_url: string; }; _source: { dashed_name: string; description: string; example: string; flat_name: string; name: string; short: string; documentation_url: string; }; _size: { dashed_name: string; description: string; example: string; flat_name: string; name: string; short: string; documentation_url: string; }; _doc_count: { dashed_name: string; description: string; example: string; flat_name: string; name: string; short: string; documentation_url: string; }; _field_names: { dashed_name: string; description: string; example: string; flat_name: string; name: string; short: string; documentation_url: string; }; _ignored: { dashed_name: string; description: string; example: string; flat_name: string; name: string; short: string; documentation_url: string; }; _routing: { dashed_name: string; description: string; example: string; flat_name: string; name: string; short: string; type: string; documentation_url: string; }; _meta: { dashed_name: string; description: string; example: string; flat_name: string; name: string; short: string; documentation_url: string; }; _tier: { dashed_name: string; description: string; example: string; flat_name: string; name: string; short: string; documentation_url: string; }; }" + ], + "path": "x-pack/plugins/fields_metadata/common/fields_metadata/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false } ], "objects": [ @@ -748,7 +803,9 @@ "StringC", "; source: ", "KeyofC", - "<{ ecs: null; integration: null; unknown: null; }>; type: ", + "<{ ecs: null; integration: null; metadata: null; unknown: null; }>; type: ", + "StringC", + "; documentation_url: ", "StringC", "; }>]>" ], diff --git a/api_docs/fields_metadata.mdx b/api_docs/fields_metadata.mdx index f2f70f8a42c22..ad808569e4a4b 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fieldsMetadata'] --- import fieldsMetadataObj from './fields_metadata.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 39 | 0 | 39 | 7 | +| 42 | 0 | 42 | 7 | ## Client diff --git a/api_docs/file_upload.mdx b/api_docs/file_upload.mdx index 0553e0d3dbd8a..4ea1b92258c46 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-07-17 +date: 2024-07-19 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 dd610ceacdf1b..07417818b283e 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-07-17 +date: 2024-07-19 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 31e6aa30ae17a..eb17854a0da57 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-07-17 +date: 2024-07-19 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 255f4072e9b72..511c54ed38939 100644 --- a/api_docs/fleet.devdocs.json +++ b/api_docs/fleet.devdocs.json @@ -4935,7 +4935,7 @@ "label": "agent_list", "description": [], "signature": [ - "({ kuery }: ", + "({ kuery, showInactive }: ", { "pluginId": "fleet", "scope": "public", @@ -4954,7 +4954,7 @@ "id": "def-public.pagePathGetters.agent_list.$1", "type": "Object", "tags": [], - "label": "{ kuery }", + "label": "{ kuery, showInactive }", "description": [], "signature": [ { @@ -7500,8 +7500,8 @@ "pluginId": "features", "scope": "server", "docId": "kibFeaturesPluginApi", - "section": "def-server.PluginSetupContract", - "text": "PluginSetupContract" + "section": "def-server.FeaturesPluginSetup", + "text": "FeaturesPluginSetup" }, " | undefined" ], @@ -19455,7 +19455,7 @@ "label": "isValidNamespace", "description": [], "signature": [ - "(namespace: string, allowBlankNamespace: boolean | undefined) => { valid: boolean; error?: string | undefined; }" + "(namespace: string, allowBlankNamespace: boolean | undefined, allowedNamespacePrefixes: string[] | undefined) => { valid: boolean; error?: string | undefined; }" ], "path": "x-pack/plugins/fleet/common/services/is_valid_namespace.ts", "deprecated": false, @@ -19490,6 +19490,21 @@ "deprecated": false, "trackAdoption": false, "isRequired": false + }, + { + "parentPluginId": "fleet", + "id": "def-common.isValidNamespace.$3", + "type": "Array", + "tags": [], + "label": "allowedNamespacePrefixes", + "description": [], + "signature": [ + "string[] | undefined" + ], + "path": "x-pack/plugins/fleet/common/services/is_valid_namespace.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false } ], "returnComment": [], diff --git a/api_docs/fleet.mdx b/api_docs/fleet.mdx index 27535110b5b80..c31c1003baa9e 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-07-17 +date: 2024-07-19 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 | |-------------------|-----------|------------------------|-----------------| -| 1349 | 5 | 1227 | 72 | +| 1350 | 5 | 1228 | 72 | ## Client diff --git a/api_docs/global_search.mdx b/api_docs/global_search.mdx index 962b310748b11..e23ed75470272 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-07-17 +date: 2024-07-19 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 955b6bd8b8cf9..a14e8cf2baa89 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-07-17 +date: 2024-07-19 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 eab071a8424c3..9e3d2a401d8ba 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-07-17 +date: 2024-07-19 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 2a5370ca28304..af32eef658793 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'imageEmbeddable'] --- import imageEmbeddableObj from './image_embeddable.devdocs.json'; diff --git a/api_docs/index_lifecycle_management.mdx b/api_docs/index_lifecycle_management.mdx index 15a30e9386919..d605d37ee9edf 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexLifecycleManagement'] --- import indexLifecycleManagementObj from './index_lifecycle_management.devdocs.json'; diff --git a/api_docs/index_management.devdocs.json b/api_docs/index_management.devdocs.json index 0f1d8d9fbc6c2..74d5df4257454 100644 --- a/api_docs/index_management.devdocs.json +++ b/api_docs/index_management.devdocs.json @@ -625,8 +625,8 @@ "pluginId": "features", "scope": "server", "docId": "kibFeaturesPluginApi", - "section": "def-server.PluginSetupContract", - "text": "PluginSetupContract" + "section": "def-server.FeaturesPluginSetup", + "text": "FeaturesPluginSetup" } ], "path": "x-pack/plugins/index_management/server/types.ts", diff --git a/api_docs/index_management.mdx b/api_docs/index_management.mdx index 7768e33e7e78d..a8799e9bfcdec 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexManagement'] --- import indexManagementObj from './index_management.devdocs.json'; diff --git a/api_docs/infra.mdx b/api_docs/infra.mdx index 7fcffecfc2617..94f8f40222170 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-07-17 +date: 2024-07-19 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 d077b49397f95..7d107b0ed3d81 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-07-17 +date: 2024-07-19 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 a395c7946d716..ce1462d6624dc 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-07-17 +date: 2024-07-19 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 33e5378123e4c..55394c4dfd0c4 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-07-17 +date: 2024-07-19 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 8c061231c9f35..c0fe82bba05c3 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'interactiveSetup'] --- import interactiveSetupObj from './interactive_setup.devdocs.json'; diff --git a/api_docs/investigate.mdx b/api_docs/investigate.mdx index 3c7dcc7f186ed..881a0e1522d9d 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'investigate'] --- import investigateObj from './investigate.devdocs.json'; diff --git a/api_docs/kbn_ace.mdx b/api_docs/kbn_ace.mdx index 41a14e9a4f288..db42d4e866907 100644 --- a/api_docs/kbn_ace.mdx +++ b/api_docs/kbn_ace.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ace title: "@kbn/ace" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ace plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ace'] --- import kbnAceObj from './kbn_ace.devdocs.json'; diff --git a/api_docs/kbn_actions_types.devdocs.json b/api_docs/kbn_actions_types.devdocs.json index 13318e7a43109..c039945f326fa 100644 --- a/api_docs/kbn_actions_types.devdocs.json +++ b/api_docs/kbn_actions_types.devdocs.json @@ -19,7 +19,116 @@ "common": { "classes": [], "functions": [], - "interfaces": [], + "interfaces": [ + { + "parentPluginId": "@kbn/actions-types", + "id": "def-common.ActionType", + "type": "Interface", + "tags": [], + "label": "ActionType", + "description": [], + "path": "packages/kbn-actions-types/action_types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/actions-types", + "id": "def-common.ActionType.id", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "path": "packages/kbn-actions-types/action_types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/actions-types", + "id": "def-common.ActionType.name", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "path": "packages/kbn-actions-types/action_types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/actions-types", + "id": "def-common.ActionType.enabled", + "type": "boolean", + "tags": [], + "label": "enabled", + "description": [], + "path": "packages/kbn-actions-types/action_types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/actions-types", + "id": "def-common.ActionType.enabledInConfig", + "type": "boolean", + "tags": [], + "label": "enabledInConfig", + "description": [], + "path": "packages/kbn-actions-types/action_types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/actions-types", + "id": "def-common.ActionType.enabledInLicense", + "type": "boolean", + "tags": [], + "label": "enabledInLicense", + "description": [], + "path": "packages/kbn-actions-types/action_types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/actions-types", + "id": "def-common.ActionType.minimumLicenseRequired", + "type": "CompoundType", + "tags": [], + "label": "minimumLicenseRequired", + "description": [], + "signature": [ + "\"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\"" + ], + "path": "packages/kbn-actions-types/action_types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/actions-types", + "id": "def-common.ActionType.supportedFeatureIds", + "type": "Array", + "tags": [], + "label": "supportedFeatureIds", + "description": [], + "signature": [ + "string[]" + ], + "path": "packages/kbn-actions-types/action_types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/actions-types", + "id": "def-common.ActionType.isSystemActionType", + "type": "boolean", + "tags": [], + "label": "isSystemActionType", + "description": [], + "path": "packages/kbn-actions-types/action_types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], "enums": [], "misc": [ { diff --git a/api_docs/kbn_actions_types.mdx b/api_docs/kbn_actions_types.mdx index 7aa8439a3b0fd..b14303eb054ef 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/actions-types'] --- import kbnActionsTypesObj from './kbn_actions_types.devdocs.json'; @@ -21,10 +21,13 @@ Contact [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-o | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 5 | 0 | 5 | 0 | +| 14 | 0 | 14 | 0 | ## Common +### Interfaces + + ### Consts, variables and types diff --git a/api_docs/kbn_aiops_components.mdx b/api_docs/kbn_aiops_components.mdx index 9a7bd8c80245b..2ad89c2711107 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-07-17 +date: 2024-07-19 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 9bd3b48e5385b..11ddb28bf56d1 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-07-17 +date: 2024-07-19 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 10439b9d954bc..22362de14acae 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-07-17 +date: 2024-07-19 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 c0c47dc90b634..624e7d41b12f0 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-07-17 +date: 2024-07-19 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 452cd7480a923..df5f38ae83864 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-07-17 +date: 2024-07-19 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 08f7e8917274c..0ede3658a340a 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-07-17 +date: 2024-07-19 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 717d1f869814b..4442c4bc3427f 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-07-17 +date: 2024-07-19 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 52f0a6e7ad969..cd3cbb198a0f6 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-07-17 +date: 2024-07-19 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 975fea44a86d5..de597886668b4 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-grouping'] --- import kbnAlertsGroupingObj from './kbn_alerts_grouping.devdocs.json'; diff --git a/api_docs/kbn_alerts_ui_shared.devdocs.json b/api_docs/kbn_alerts_ui_shared.devdocs.json index 404c573dafc06..11b22945db422 100644 --- a/api_docs/kbn_alerts_ui_shared.devdocs.json +++ b/api_docs/kbn_alerts_ui_shared.devdocs.json @@ -6130,6 +6130,37 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/alerts-ui-shared", + "id": "def-common.SanitizedRuleAction", + "type": "Type", + "tags": [], + "label": "SanitizedRuleAction", + "description": [], + "signature": [ + "Omit<", + { + "pluginId": "@kbn/alerting-types", + "scope": "common", + "docId": "kibKbnAlertingTypesPluginApi", + "section": "def-common.RuleAction", + "text": "RuleAction" + }, + ", \"alertsFilter\"> & { alertsFilter?: ", + { + "pluginId": "@kbn/alerting-types", + "scope": "common", + "docId": "kibKbnAlertingTypesPluginApi", + "section": "def-common.SanitizedAlertsFilter", + "text": "SanitizedAlertsFilter" + }, + " | undefined; }" + ], + "path": "packages/kbn-alerting-types/rule_types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/alerts-ui-shared", "id": "def-common.SystemAction", diff --git a/api_docs/kbn_alerts_ui_shared.mdx b/api_docs/kbn_alerts_ui_shared.mdx index 56a9a4f01d965..92b9142f729f5 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-ui-shared'] --- import kbnAlertsUiSharedObj from './kbn_alerts_ui_shared.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-o | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 299 | 0 | 283 | 8 | +| 300 | 0 | 284 | 8 | ## Common diff --git a/api_docs/kbn_analytics.mdx b/api_docs/kbn_analytics.mdx index 66ac7d2a677e8..8eff71adc2585 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-07-17 +date: 2024-07-19 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 746db04887755..359f20d1f918a 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-07-17 +date: 2024-07-19 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 4f37e41d41f3f..50a433199a3fa 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-07-17 +date: 2024-07-19 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 8c618b8485ed7..58b12f6e7c1e9 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-07-17 +date: 2024-07-19 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 fa79f888f2c70..54cdd42fa2978 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-07-17 +date: 2024-07-19 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 2901b4de42720..09646b0965e2a 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace-client'] --- import kbnApmSynthtraceClientObj from './kbn_apm_synthtrace_client.devdocs.json'; diff --git a/api_docs/kbn_apm_utils.mdx b/api_docs/kbn_apm_utils.mdx index 5adb2dbe2dc93..32450077ae9c4 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-utils'] --- import kbnApmUtilsObj from './kbn_apm_utils.devdocs.json'; diff --git a/api_docs/kbn_avc_banner.devdocs.json b/api_docs/kbn_avc_banner.devdocs.json new file mode 100644 index 0000000000000..e86dac6904afb --- /dev/null +++ b/api_docs/kbn_avc_banner.devdocs.json @@ -0,0 +1,61 @@ +{ + "id": "@kbn/avc-banner", + "client": { + "classes": [], + "functions": [ + { + "parentPluginId": "@kbn/avc-banner", + "id": "def-public.AVCResultsBanner2024", + "type": "Function", + "tags": [], + "label": "AVCResultsBanner2024", + "description": [], + "signature": [ + "({ onDismiss }: React.PropsWithChildren<{ onDismiss: () => void; }>) => JSX.Element" + ], + "path": "packages/kbn-avc-banner/src/index.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/avc-banner", + "id": "def-public.AVCResultsBanner2024.$1", + "type": "CompoundType", + "tags": [], + "label": "{ onDismiss }", + "description": [], + "signature": [ + "React.PropsWithChildren<{ onDismiss: () => void; }>" + ], + "path": "packages/kbn-avc-banner/src/index.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_avc_banner.mdx b/api_docs/kbn_avc_banner.mdx new file mode 100644 index 0000000000000..ed9959de1f8b4 --- /dev/null +++ b/api_docs/kbn_avc_banner.mdx @@ -0,0 +1,30 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibKbnAvcBannerPluginApi +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-07-19 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/avc-banner'] +--- +import kbnAvcBannerObj from './kbn_avc_banner.devdocs.json'; + + + +Contact [@elastic/security-defend-workflows](https://github.com/orgs/elastic/teams/security-defend-workflows) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 2 | 0 | 2 | 0 | + +## Client + +### Functions + + diff --git a/api_docs/kbn_axe_config.mdx b/api_docs/kbn_axe_config.mdx index d6301509dfa0e..a990e689ee3c3 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-07-17 +date: 2024-07-19 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 f2222680ee963..bac45fb92f3f7 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-07-17 +date: 2024-07-19 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 06671ea8e327f..82d3ee161ee5c 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-07-17 +date: 2024-07-19 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 7ea08bd76aedd..8168226db6646 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-07-17 +date: 2024-07-19 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 3c5161fe55783..7dca958150e3c 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cases-components'] --- import kbnCasesComponentsObj from './kbn_cases_components.devdocs.json'; diff --git a/api_docs/kbn_cell_actions.mdx b/api_docs/kbn_cell_actions.mdx index 1ba964b9a2749..dd9ebeffae585 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-07-17 +date: 2024-07-19 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 73056bece29cd..50aa551ef29f8 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-07-17 +date: 2024-07-19 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 7e0080fa059b6..963041c111dec 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-07-17 +date: 2024-07-19 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 590e5d155d298..696e691bfc13f 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-07-17 +date: 2024-07-19 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 03bb4ef85b78d..da44eb4e7b119 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-07-17 +date: 2024-07-19 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 5990ce80fe45b..93035a5a8103c 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-07-17 +date: 2024-07-19 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 3d2161cc1ce73..5160f562194fe 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cli-dev-mode'] --- import kbnCliDevModeObj from './kbn_cli_dev_mode.devdocs.json'; diff --git a/api_docs/kbn_code_editor.mdx b/api_docs/kbn_code_editor.mdx index be54f47766a46..16938338a5336 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-07-17 +date: 2024-07-19 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 77af4f3a99a7f..a4c7d2d6ab13f 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-07-17 +date: 2024-07-19 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 2e076d1460b1a..4783f6f7e1b96 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-07-17 +date: 2024-07-19 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 003a10ec4cb6b..8f841ec64dca6 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-07-17 +date: 2024-07-19 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 15227bb388ece..b187f8bc1f686 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-07-17 +date: 2024-07-19 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 813a201688b81..36820e7b2cffc 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-07-17 +date: 2024-07-19 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 2f4fa752a19b8..63f5f47ff64d8 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-07-17 +date: 2024-07-19 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 f70786641206c..69536ce2dc4e6 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-content-editor'] --- import kbnContentManagementContentEditorObj from './kbn_content_management_content_editor.devdocs.json'; diff --git a/api_docs/kbn_content_management_tabbed_table_list_view.mdx b/api_docs/kbn_content_management_tabbed_table_list_view.mdx index 6cc85204bd211..85318c9ed9525 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-07-17 +date: 2024-07-19 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 47c6aafb5f126..3f45d495f244d 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-07-17 +date: 2024-07-19 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 aa5a1db5a7b2f..a4650b8ebf6c0 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-07-17 +date: 2024-07-19 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 dcffab9efd97b..62bdfc187336e 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-07-17 +date: 2024-07-19 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 8f28c1ace18eb..8e31bebdff6a2 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-07-17 +date: 2024-07-19 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 c9f2747d424bb..67a81178dae98 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-07-17 +date: 2024-07-19 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 653be84cc5687..62d5ffc64355a 100644 --- a/api_docs/kbn_core_analytics_browser.devdocs.json +++ b/api_docs/kbn_core_analytics_browser.devdocs.json @@ -744,8 +744,8 @@ "path": "x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_client.ts" }, { - "plugin": "elasticAssistant", - "path": "x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.ts" + "plugin": "datasetQuality", + "path": "x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_client.ts" }, { "plugin": "elasticAssistant", @@ -753,7 +753,7 @@ }, { "plugin": "elasticAssistant", - "path": "x-pack/plugins/elastic_assistant/server/routes/attack_discovery/helpers.ts" + "path": "x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.ts" }, { "plugin": "elasticAssistant", @@ -769,7 +769,7 @@ }, { "plugin": "elasticAssistant", - "path": "x-pack/plugins/elastic_assistant/server/routes/helpers.ts" + "path": "x-pack/plugins/elastic_assistant/server/routes/attack_discovery/helpers.ts" }, { "plugin": "elasticAssistant", @@ -1327,6 +1327,14 @@ "plugin": "datasetQuality", "path": "x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_service.test.ts" }, + { + "plugin": "datasetQuality", + "path": "x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "datasetQuality", + "path": "x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_service.test.ts" + }, { "plugin": "infra", "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" diff --git a/api_docs/kbn_core_analytics_browser.mdx b/api_docs/kbn_core_analytics_browser.mdx index f29e01e4f2d6b..ae9191b51fcf7 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-07-17 +date: 2024-07-19 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 988af280d2500..72ab9539cabfc 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-07-17 +date: 2024-07-19 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 e6d2bfa34ce59..9f532c9c8b744 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-07-17 +date: 2024-07-19 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 ea8766e2c7639..c3322190aa47d 100644 --- a/api_docs/kbn_core_analytics_server.devdocs.json +++ b/api_docs/kbn_core_analytics_server.devdocs.json @@ -744,8 +744,8 @@ "path": "x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_client.ts" }, { - "plugin": "elasticAssistant", - "path": "x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.ts" + "plugin": "datasetQuality", + "path": "x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_client.ts" }, { "plugin": "elasticAssistant", @@ -753,7 +753,7 @@ }, { "plugin": "elasticAssistant", - "path": "x-pack/plugins/elastic_assistant/server/routes/attack_discovery/helpers.ts" + "path": "x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.ts" }, { "plugin": "elasticAssistant", @@ -769,7 +769,7 @@ }, { "plugin": "elasticAssistant", - "path": "x-pack/plugins/elastic_assistant/server/routes/helpers.ts" + "path": "x-pack/plugins/elastic_assistant/server/routes/attack_discovery/helpers.ts" }, { "plugin": "elasticAssistant", @@ -1327,6 +1327,14 @@ "plugin": "datasetQuality", "path": "x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_service.test.ts" }, + { + "plugin": "datasetQuality", + "path": "x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "datasetQuality", + "path": "x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_service.test.ts" + }, { "plugin": "infra", "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" diff --git a/api_docs/kbn_core_analytics_server.mdx b/api_docs/kbn_core_analytics_server.mdx index b6fb697f3ba46..bd143a110d0bb 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-07-17 +date: 2024-07-19 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 3300aa7dd3922..77e3f890a475c 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-07-17 +date: 2024-07-19 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 dd595bb9ed7f5..0d5b434b4be66 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-07-17 +date: 2024-07-19 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 265d1b6b0d5c2..322764bdb0351 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-07-17 +date: 2024-07-19 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 eb8591a0a8362..5b16f0564763c 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-07-17 +date: 2024-07-19 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 414c2cffaf930..5f52dfd605311 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-07-17 +date: 2024-07-19 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 10c4c733b126c..fd6c665594393 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-07-17 +date: 2024-07-19 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 b83c28ec2d8c8..43a80a7bcc480 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-07-17 +date: 2024-07-19 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 ec0182a1f97ec..b9bfa3ffb8d47 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-07-17 +date: 2024-07-19 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 91700e0240eab..dc36ece45388d 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-07-17 +date: 2024-07-19 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 5fcaf6d812c16..766d30ffafb13 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-07-17 +date: 2024-07-19 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 e61bef9158603..b589889b53576 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-07-17 +date: 2024-07-19 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 88f1e7fbc4180..205f37e56be4f 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-07-17 +date: 2024-07-19 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 6a2f352ac9b68..a6978ce29e3c6 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-07-17 +date: 2024-07-19 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 c681bf6e7fad2..7744797e4bee6 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-07-17 +date: 2024-07-19 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 a8f9e6042e1da..a68a13c75f37d 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-07-17 +date: 2024-07-19 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 927d0cb0717f2..04870c0542508 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-07-17 +date: 2024-07-19 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 c5347fd761a23..808e385897d44 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-07-17 +date: 2024-07-19 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 9282b95fe7034..8bcf5bb7ca4b3 100644 --- a/api_docs/kbn_core_chrome_browser.devdocs.json +++ b/api_docs/kbn_core_chrome_browser.devdocs.json @@ -3649,7 +3649,7 @@ "tags": [], "label": "homePage", "description": [ - "The page to navigate to when switching to this solution navigation." + "The page to navigate to when clicking on the Kibana (or custom) logo." ], "signature": [ "LinkId | undefined" diff --git a/api_docs/kbn_core_chrome_browser.mdx b/api_docs/kbn_core_chrome_browser.mdx index f80460e2d0ca6..72ad7dfd5c30e 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-07-17 +date: 2024-07-19 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 e15c807ad3b6d..659daae0a73f9 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-07-17 +date: 2024-07-19 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 c285cb0bdbcd7..dfa48ad4f345f 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-07-17 +date: 2024-07-19 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 5d32aafea7771..8af6048480698 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-07-17 +date: 2024-07-19 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 e109d197aaaf6..54ce7b53e0c91 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-07-17 +date: 2024-07-19 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 5ecfa858874fb..743a98ba3daa6 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-07-17 +date: 2024-07-19 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 fdfcf909da869..d020e553215fa 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-07-17 +date: 2024-07-19 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 56a87990e13c6..1ec38de008dcb 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-07-17 +date: 2024-07-19 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 b0d242533001b..d01498862947a 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-07-17 +date: 2024-07-19 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 c7dd7df68c7dc..bb4cfc7cd7645 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-07-17 +date: 2024-07-19 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 cc1e8f2af249f..e4d7ff55c5f2f 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-07-17 +date: 2024-07-19 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 4ecb5c78b5ac0..9e71e578b4999 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-07-17 +date: 2024-07-19 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 367d5765a39fa..f6f4a3261c2a6 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-07-17 +date: 2024-07-19 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 8aa0ae49b7690..a09431cad6fe6 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-07-17 +date: 2024-07-19 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 51d54a50f846f..86801047243a4 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-07-17 +date: 2024-07-19 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 a2b34547a0cdf..f1f7b3916d3f7 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-07-17 +date: 2024-07-19 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 23d258b5fa983..022702f3dbc3b 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-07-17 +date: 2024-07-19 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 82c15c2cfc236..a8005ce092e4f 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-07-17 +date: 2024-07-19 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 d5ca1546448a5..3f14284f2aa99 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-07-17 +date: 2024-07-19 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 8dc30c0ba33d7..e7efa6f2e24db 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-07-17 +date: 2024-07-19 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 a564532d8bbce..5470195747b90 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-07-17 +date: 2024-07-19 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 a1c6ed25ccf4e..184b087575244 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-07-17 +date: 2024-07-19 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 9ef1bbcd2ea20..88d3296f9c601 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-07-17 +date: 2024-07-19 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 ec28134a14950..ae7a0132f05e8 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-07-17 +date: 2024-07-19 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 8b4ab51496d4b..cf3f81c943b00 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-07-17 +date: 2024-07-19 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 61affead965ea..7485589ef5bca 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-07-17 +date: 2024-07-19 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 3d6fb32b21dff..26d8f8aa2d28e 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-07-17 +date: 2024-07-19 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 14a2fa42dc1ed..c4ee39583ecae 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-07-17 +date: 2024-07-19 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 e32ffd6dd5522..25c5f05748993 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-07-17 +date: 2024-07-19 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 ab0128ad25dec..f47dd0b95cdd8 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-07-17 +date: 2024-07-19 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 adcd207daa843..c4a2e1c65cff8 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-07-17 +date: 2024-07-19 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 80a0efc8a88b7..8bc2931652711 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-07-17 +date: 2024-07-19 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 2740e7eefbc51..9cf9e5e9fb4c4 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-07-17 +date: 2024-07-19 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 97c3f87bd225a..753c44cb3f41f 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-07-17 +date: 2024-07-19 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 54c1dabdd6bd0..c240274c7fb52 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-07-17 +date: 2024-07-19 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 5a6b091c532d5..e083a8825c09f 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-07-17 +date: 2024-07-19 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 ca3c1ef293f8d..56f9bc1963aaf 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-fatal-errors-browser-mocks'] --- import kbnCoreFatalErrorsBrowserMocksObj from './kbn_core_fatal_errors_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser.mdx b/api_docs/kbn_core_http_browser.mdx index 7784dcf0d05ce..5b019543ceac3 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-07-17 +date: 2024-07-19 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 53b53082c87e8..d67d52061d79f 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-07-17 +date: 2024-07-19 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 d3694b9acac16..81b743a31a7ec 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-07-17 +date: 2024-07-19 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 f9cb4dc55dbb2..6c5d05edfe61f 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-07-17 +date: 2024-07-19 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 d45588abf5d56..42bb9474a1a53 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-07-17 +date: 2024-07-19 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 4b7a179b2f547..6e2bb268f380a 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-07-17 +date: 2024-07-19 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 cefcb7e729eb8..f8b44deed75b8 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-07-17 +date: 2024-07-19 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 dce53b46ab0fa..7758c6d58aa73 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-07-17 +date: 2024-07-19 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 343f4ab39dab1..9cf4a14d4f9d2 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-07-17 +date: 2024-07-19 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 d37df5b58afa0..7c0bf4421c8c2 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-07-17 +date: 2024-07-19 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 845f919175bdb..91d7275f60e00 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-07-17 +date: 2024-07-19 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 97fa049ab1751..50184b2fb7e17 100644 --- a/api_docs/kbn_core_http_server.devdocs.json +++ b/api_docs/kbn_core_http_server.devdocs.json @@ -4742,10 +4742,6 @@ "plugin": "grokdebugger", "path": "x-pack/plugins/grokdebugger/server/lib/kibana_framework.ts" }, - { - "plugin": "entityManager", - "path": "x-pack/plugins/observability_solution/entity_manager/server/routes/ping.ts" - }, { "plugin": "entityManager", "path": "x-pack/plugins/observability_solution/entity_manager/server/routes/entities/get.ts" @@ -14066,7 +14062,7 @@ "tags": [], "label": "VersionedRouter", "description": [ - "\nA router, very similar to {@link IRouter} that will return an {@link VersionedRoute}\ninstead.\n" + "\nA router, very similar to {@link IRouter} that will return an {@link VersionedRoute}\ninstead\n" ], "signature": [ { diff --git a/api_docs/kbn_core_http_server.mdx b/api_docs/kbn_core_http_server.mdx index 84cb864f2eb20..f010898bf99f8 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server'] --- import kbnCoreHttpServerObj from './kbn_core_http_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_server_internal.mdx b/api_docs/kbn_core_http_server_internal.mdx index 68dbeaa8d17cf..2a38077023452 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server-internal'] --- import kbnCoreHttpServerInternalObj from './kbn_core_http_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_server_mocks.mdx b/api_docs/kbn_core_http_server_mocks.mdx index d347254d0e2fb..b5c1c2bf06d2b 100644 --- a/api_docs/kbn_core_http_server_mocks.mdx +++ b/api_docs/kbn_core_http_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-mocks title: "@kbn/core-http-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-mocks plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server-mocks'] --- import kbnCoreHttpServerMocksObj from './kbn_core_http_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_browser.mdx b/api_docs/kbn_core_i18n_browser.mdx index fd189ede8bd07..d2c9cda23816e 100644 --- a/api_docs/kbn_core_i18n_browser.mdx +++ b/api_docs/kbn_core_i18n_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser title: "@kbn/core-i18n-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-browser'] --- import kbnCoreI18nBrowserObj from './kbn_core_i18n_browser.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_browser_mocks.mdx b/api_docs/kbn_core_i18n_browser_mocks.mdx index 8c830de4b04d8..925ce134eec33 100644 --- a/api_docs/kbn_core_i18n_browser_mocks.mdx +++ b/api_docs/kbn_core_i18n_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser-mocks title: "@kbn/core-i18n-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser-mocks plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-browser-mocks'] --- import kbnCoreI18nBrowserMocksObj from './kbn_core_i18n_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server.mdx b/api_docs/kbn_core_i18n_server.mdx index b1b99a5c90f38..495d79309c1aa 100644 --- a/api_docs/kbn_core_i18n_server.mdx +++ b/api_docs/kbn_core_i18n_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server title: "@kbn/core-i18n-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server'] --- import kbnCoreI18nServerObj from './kbn_core_i18n_server.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server_internal.mdx b/api_docs/kbn_core_i18n_server_internal.mdx index 74a94894c69b7..36cdcf1e1ce5b 100644 --- a/api_docs/kbn_core_i18n_server_internal.mdx +++ b/api_docs/kbn_core_i18n_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server-internal title: "@kbn/core-i18n-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server-internal plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server-internal'] --- import kbnCoreI18nServerInternalObj from './kbn_core_i18n_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server_mocks.mdx b/api_docs/kbn_core_i18n_server_mocks.mdx index 8b354a488c76b..9a56e2f8c0917 100644 --- a/api_docs/kbn_core_i18n_server_mocks.mdx +++ b/api_docs/kbn_core_i18n_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server-mocks title: "@kbn/core-i18n-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server-mocks plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server-mocks'] --- import kbnCoreI18nServerMocksObj from './kbn_core_i18n_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx index 82a92c55d5386..2d3deb88e7224 100644 --- a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx +++ b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-injected-metadata-browser-mocks title: "@kbn/core-injected-metadata-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-injected-metadata-browser-mocks plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-injected-metadata-browser-mocks'] --- import kbnCoreInjectedMetadataBrowserMocksObj from './kbn_core_injected_metadata_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_integrations_browser_internal.mdx b/api_docs/kbn_core_integrations_browser_internal.mdx index 4748f5ad40cc6..26df5fe8a3991 100644 --- a/api_docs/kbn_core_integrations_browser_internal.mdx +++ b/api_docs/kbn_core_integrations_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-internal title: "@kbn/core-integrations-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-internal plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-integrations-browser-internal'] --- import kbnCoreIntegrationsBrowserInternalObj from './kbn_core_integrations_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_integrations_browser_mocks.mdx b/api_docs/kbn_core_integrations_browser_mocks.mdx index ff3be82f93ac5..51c426fd2a601 100644 --- a/api_docs/kbn_core_integrations_browser_mocks.mdx +++ b/api_docs/kbn_core_integrations_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-mocks title: "@kbn/core-integrations-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-mocks plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-integrations-browser-mocks'] --- import kbnCoreIntegrationsBrowserMocksObj from './kbn_core_integrations_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_browser.mdx b/api_docs/kbn_core_lifecycle_browser.mdx index 39d2aed6bbc24..ac13c3f3e46d3 100644 --- a/api_docs/kbn_core_lifecycle_browser.mdx +++ b/api_docs/kbn_core_lifecycle_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-browser title: "@kbn/core-lifecycle-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-browser plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-browser'] --- import kbnCoreLifecycleBrowserObj from './kbn_core_lifecycle_browser.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_browser_mocks.mdx b/api_docs/kbn_core_lifecycle_browser_mocks.mdx index 5e327d67c4af1..39892e0a1973d 100644 --- a/api_docs/kbn_core_lifecycle_browser_mocks.mdx +++ b/api_docs/kbn_core_lifecycle_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-browser-mocks title: "@kbn/core-lifecycle-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-browser-mocks plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-browser-mocks'] --- import kbnCoreLifecycleBrowserMocksObj from './kbn_core_lifecycle_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_server.mdx b/api_docs/kbn_core_lifecycle_server.mdx index 2797c59cf3313..14ae525d0ff86 100644 --- a/api_docs/kbn_core_lifecycle_server.mdx +++ b/api_docs/kbn_core_lifecycle_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-server title: "@kbn/core-lifecycle-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-server plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-server'] --- import kbnCoreLifecycleServerObj from './kbn_core_lifecycle_server.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_server_mocks.mdx b/api_docs/kbn_core_lifecycle_server_mocks.mdx index b730e0a4d5b62..c51c586187074 100644 --- a/api_docs/kbn_core_lifecycle_server_mocks.mdx +++ b/api_docs/kbn_core_lifecycle_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-server-mocks title: "@kbn/core-lifecycle-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-server-mocks plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-server-mocks'] --- import kbnCoreLifecycleServerMocksObj from './kbn_core_lifecycle_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_logging_browser_mocks.mdx b/api_docs/kbn_core_logging_browser_mocks.mdx index 450f4aabb2fbf..983f345d7822a 100644 --- a/api_docs/kbn_core_logging_browser_mocks.mdx +++ b/api_docs/kbn_core_logging_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-browser-mocks title: "@kbn/core-logging-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-browser-mocks plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-browser-mocks'] --- import kbnCoreLoggingBrowserMocksObj from './kbn_core_logging_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_logging_common_internal.mdx b/api_docs/kbn_core_logging_common_internal.mdx index dfdb631b5808c..c76595e73bfd9 100644 --- a/api_docs/kbn_core_logging_common_internal.mdx +++ b/api_docs/kbn_core_logging_common_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-common-internal title: "@kbn/core-logging-common-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-common-internal plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-common-internal'] --- import kbnCoreLoggingCommonInternalObj from './kbn_core_logging_common_internal.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server.mdx b/api_docs/kbn_core_logging_server.mdx index aab517a9c4737..a9d8b39e75a44 100644 --- a/api_docs/kbn_core_logging_server.mdx +++ b/api_docs/kbn_core_logging_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server title: "@kbn/core-logging-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server'] --- import kbnCoreLoggingServerObj from './kbn_core_logging_server.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server_internal.mdx b/api_docs/kbn_core_logging_server_internal.mdx index 1ad2b2b66ddd5..8dc678a5aec37 100644 --- a/api_docs/kbn_core_logging_server_internal.mdx +++ b/api_docs/kbn_core_logging_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-internal title: "@kbn/core-logging-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-internal plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server-internal'] --- import kbnCoreLoggingServerInternalObj from './kbn_core_logging_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server_mocks.mdx b/api_docs/kbn_core_logging_server_mocks.mdx index 42bcc075e2e23..92fbfaf7c33b9 100644 --- a/api_docs/kbn_core_logging_server_mocks.mdx +++ b/api_docs/kbn_core_logging_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-mocks title: "@kbn/core-logging-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-mocks plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server-mocks'] --- import kbnCoreLoggingServerMocksObj from './kbn_core_logging_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_collectors_server_internal.mdx b/api_docs/kbn_core_metrics_collectors_server_internal.mdx index 72bcaef8443e9..1a0e1344d2b81 100644 --- a/api_docs/kbn_core_metrics_collectors_server_internal.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-internal title: "@kbn/core-metrics-collectors-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-internal plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-collectors-server-internal'] --- import kbnCoreMetricsCollectorsServerInternalObj from './kbn_core_metrics_collectors_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx index f7b4667c16c3f..8f74d4fa960df 100644 --- a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-mocks title: "@kbn/core-metrics-collectors-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-mocks plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-collectors-server-mocks'] --- import kbnCoreMetricsCollectorsServerMocksObj from './kbn_core_metrics_collectors_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server.mdx b/api_docs/kbn_core_metrics_server.mdx index 2cab4d2e2678b..45a839cf05d65 100644 --- a/api_docs/kbn_core_metrics_server.mdx +++ b/api_docs/kbn_core_metrics_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server title: "@kbn/core-metrics-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server'] --- import kbnCoreMetricsServerObj from './kbn_core_metrics_server.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server_internal.mdx b/api_docs/kbn_core_metrics_server_internal.mdx index 98f88e15f7996..7227081e751d2 100644 --- a/api_docs/kbn_core_metrics_server_internal.mdx +++ b/api_docs/kbn_core_metrics_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-internal title: "@kbn/core-metrics-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-internal plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-internal'] --- import kbnCoreMetricsServerInternalObj from './kbn_core_metrics_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server_mocks.mdx b/api_docs/kbn_core_metrics_server_mocks.mdx index cdb08306a473d..7ba6b55f0aa8b 100644 --- a/api_docs/kbn_core_metrics_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-mocks title: "@kbn/core-metrics-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-mocks plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-mocks'] --- import kbnCoreMetricsServerMocksObj from './kbn_core_metrics_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_mount_utils_browser.mdx b/api_docs/kbn_core_mount_utils_browser.mdx index 6de20ab619514..dcae2aaeae8a1 100644 --- a/api_docs/kbn_core_mount_utils_browser.mdx +++ b/api_docs/kbn_core_mount_utils_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-mount-utils-browser title: "@kbn/core-mount-utils-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-mount-utils-browser plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-mount-utils-browser'] --- import kbnCoreMountUtilsBrowserObj from './kbn_core_mount_utils_browser.devdocs.json'; diff --git a/api_docs/kbn_core_node_server.mdx b/api_docs/kbn_core_node_server.mdx index 5725639f6c689..d2a645791c67d 100644 --- a/api_docs/kbn_core_node_server.mdx +++ b/api_docs/kbn_core_node_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server title: "@kbn/core-node-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server'] --- import kbnCoreNodeServerObj from './kbn_core_node_server.devdocs.json'; diff --git a/api_docs/kbn_core_node_server_internal.mdx b/api_docs/kbn_core_node_server_internal.mdx index bf6ba2c6e77ef..244d62cb3c058 100644 --- a/api_docs/kbn_core_node_server_internal.mdx +++ b/api_docs/kbn_core_node_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-internal title: "@kbn/core-node-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-internal plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server-internal'] --- import kbnCoreNodeServerInternalObj from './kbn_core_node_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_node_server_mocks.mdx b/api_docs/kbn_core_node_server_mocks.mdx index 5e98462e511f0..fb4a4359c8871 100644 --- a/api_docs/kbn_core_node_server_mocks.mdx +++ b/api_docs/kbn_core_node_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-mocks title: "@kbn/core-node-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-mocks plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server-mocks'] --- import kbnCoreNodeServerMocksObj from './kbn_core_node_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser.mdx b/api_docs/kbn_core_notifications_browser.mdx index df16455320006..25880f70e0fbd 100644 --- a/api_docs/kbn_core_notifications_browser.mdx +++ b/api_docs/kbn_core_notifications_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser title: "@kbn/core-notifications-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser'] --- import kbnCoreNotificationsBrowserObj from './kbn_core_notifications_browser.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser_internal.mdx b/api_docs/kbn_core_notifications_browser_internal.mdx index c531ef2fe9c74..6cca423f11ec7 100644 --- a/api_docs/kbn_core_notifications_browser_internal.mdx +++ b/api_docs/kbn_core_notifications_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-internal title: "@kbn/core-notifications-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-internal plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser-internal'] --- import kbnCoreNotificationsBrowserInternalObj from './kbn_core_notifications_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser_mocks.mdx b/api_docs/kbn_core_notifications_browser_mocks.mdx index a84a85c86c09f..2c9c71a5c1d41 100644 --- a/api_docs/kbn_core_notifications_browser_mocks.mdx +++ b/api_docs/kbn_core_notifications_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-mocks title: "@kbn/core-notifications-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-mocks plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser-mocks'] --- import kbnCoreNotificationsBrowserMocksObj from './kbn_core_notifications_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser.mdx b/api_docs/kbn_core_overlays_browser.mdx index e24222c19d0b4..55f0c17fb4ac9 100644 --- a/api_docs/kbn_core_overlays_browser.mdx +++ b/api_docs/kbn_core_overlays_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser title: "@kbn/core-overlays-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser'] --- import kbnCoreOverlaysBrowserObj from './kbn_core_overlays_browser.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser_internal.mdx b/api_docs/kbn_core_overlays_browser_internal.mdx index 04b043e0f5ba4..3a81d2c79ef95 100644 --- a/api_docs/kbn_core_overlays_browser_internal.mdx +++ b/api_docs/kbn_core_overlays_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-internal title: "@kbn/core-overlays-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-internal plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser-internal'] --- import kbnCoreOverlaysBrowserInternalObj from './kbn_core_overlays_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser_mocks.mdx b/api_docs/kbn_core_overlays_browser_mocks.mdx index 2b74717ffe5ac..d5b2efa9b46c0 100644 --- a/api_docs/kbn_core_overlays_browser_mocks.mdx +++ b/api_docs/kbn_core_overlays_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-mocks title: "@kbn/core-overlays-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-mocks plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser-mocks'] --- import kbnCoreOverlaysBrowserMocksObj from './kbn_core_overlays_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_browser.mdx b/api_docs/kbn_core_plugins_browser.mdx index 55c95b6d2cb45..08da9bb0fcfed 100644 --- a/api_docs/kbn_core_plugins_browser.mdx +++ b/api_docs/kbn_core_plugins_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-browser title: "@kbn/core-plugins-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-browser plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-browser'] --- import kbnCorePluginsBrowserObj from './kbn_core_plugins_browser.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_browser_mocks.mdx b/api_docs/kbn_core_plugins_browser_mocks.mdx index 859843631effa..0b1e64f9abb8e 100644 --- a/api_docs/kbn_core_plugins_browser_mocks.mdx +++ b/api_docs/kbn_core_plugins_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-browser-mocks title: "@kbn/core-plugins-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-browser-mocks plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-browser-mocks'] --- import kbnCorePluginsBrowserMocksObj from './kbn_core_plugins_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_contracts_browser.mdx b/api_docs/kbn_core_plugins_contracts_browser.mdx index 7824706870f87..136e1192c7511 100644 --- a/api_docs/kbn_core_plugins_contracts_browser.mdx +++ b/api_docs/kbn_core_plugins_contracts_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-contracts-browser title: "@kbn/core-plugins-contracts-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-contracts-browser plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-contracts-browser'] --- import kbnCorePluginsContractsBrowserObj from './kbn_core_plugins_contracts_browser.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_contracts_server.mdx b/api_docs/kbn_core_plugins_contracts_server.mdx index f7ef46debd125..e933bb61ece91 100644 --- a/api_docs/kbn_core_plugins_contracts_server.mdx +++ b/api_docs/kbn_core_plugins_contracts_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-contracts-server title: "@kbn/core-plugins-contracts-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-contracts-server plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-contracts-server'] --- import kbnCorePluginsContractsServerObj from './kbn_core_plugins_contracts_server.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_server.mdx b/api_docs/kbn_core_plugins_server.mdx index 6d03227a70d37..b4968964f04ec 100644 --- a/api_docs/kbn_core_plugins_server.mdx +++ b/api_docs/kbn_core_plugins_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-server title: "@kbn/core-plugins-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-server plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-server'] --- import kbnCorePluginsServerObj from './kbn_core_plugins_server.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_server_mocks.mdx b/api_docs/kbn_core_plugins_server_mocks.mdx index 4675675b6a6bf..8b2746c0bb329 100644 --- a/api_docs/kbn_core_plugins_server_mocks.mdx +++ b/api_docs/kbn_core_plugins_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-server-mocks title: "@kbn/core-plugins-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-server-mocks plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-server-mocks'] --- import kbnCorePluginsServerMocksObj from './kbn_core_plugins_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_preboot_server.mdx b/api_docs/kbn_core_preboot_server.mdx index 12f6db3e22bad..5fe9ed52dac14 100644 --- a/api_docs/kbn_core_preboot_server.mdx +++ b/api_docs/kbn_core_preboot_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server title: "@kbn/core-preboot-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-preboot-server'] --- import kbnCorePrebootServerObj from './kbn_core_preboot_server.devdocs.json'; diff --git a/api_docs/kbn_core_preboot_server_mocks.mdx b/api_docs/kbn_core_preboot_server_mocks.mdx index 466d4bb5fbdea..8bf44c7d8f152 100644 --- a/api_docs/kbn_core_preboot_server_mocks.mdx +++ b/api_docs/kbn_core_preboot_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server-mocks title: "@kbn/core-preboot-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server-mocks plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-preboot-server-mocks'] --- import kbnCorePrebootServerMocksObj from './kbn_core_preboot_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_browser_mocks.mdx b/api_docs/kbn_core_rendering_browser_mocks.mdx index 172063046f418..e152bbcba2cd3 100644 --- a/api_docs/kbn_core_rendering_browser_mocks.mdx +++ b/api_docs/kbn_core_rendering_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-browser-mocks title: "@kbn/core-rendering-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-browser-mocks plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-browser-mocks'] --- import kbnCoreRenderingBrowserMocksObj from './kbn_core_rendering_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_server_internal.mdx b/api_docs/kbn_core_rendering_server_internal.mdx index 385f24a4f8aa7..1b8e786da4d07 100644 --- a/api_docs/kbn_core_rendering_server_internal.mdx +++ b/api_docs/kbn_core_rendering_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-server-internal title: "@kbn/core-rendering-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-server-internal plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-server-internal'] --- import kbnCoreRenderingServerInternalObj from './kbn_core_rendering_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_server_mocks.mdx b/api_docs/kbn_core_rendering_server_mocks.mdx index f33542c7dbc32..4aa48e64b790a 100644 --- a/api_docs/kbn_core_rendering_server_mocks.mdx +++ b/api_docs/kbn_core_rendering_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-server-mocks title: "@kbn/core-rendering-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-server-mocks plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-server-mocks'] --- import kbnCoreRenderingServerMocksObj from './kbn_core_rendering_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_root_server_internal.mdx b/api_docs/kbn_core_root_server_internal.mdx index 824cfaf0e4adf..6e4025ba62bb3 100644 --- a/api_docs/kbn_core_root_server_internal.mdx +++ b/api_docs/kbn_core_root_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-root-server-internal title: "@kbn/core-root-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-root-server-internal plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-root-server-internal'] --- import kbnCoreRootServerInternalObj from './kbn_core_root_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_browser.mdx b/api_docs/kbn_core_saved_objects_api_browser.mdx index 07dafe2bef44d..42c1d8d5054b2 100644 --- a/api_docs/kbn_core_saved_objects_api_browser.mdx +++ b/api_docs/kbn_core_saved_objects_api_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-browser title: "@kbn/core-saved-objects-api-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-browser plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-browser'] --- import kbnCoreSavedObjectsApiBrowserObj from './kbn_core_saved_objects_api_browser.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_server.mdx b/api_docs/kbn_core_saved_objects_api_server.mdx index 006dfc53b34aa..a8d80ebe07b7f 100644 --- a/api_docs/kbn_core_saved_objects_api_server.mdx +++ b/api_docs/kbn_core_saved_objects_api_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server title: "@kbn/core-saved-objects-api-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server'] --- import kbnCoreSavedObjectsApiServerObj from './kbn_core_saved_objects_api_server.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_server_mocks.mdx b/api_docs/kbn_core_saved_objects_api_server_mocks.mdx index 162087a4b1db4..bd0aa5112b7fc 100644 --- a/api_docs/kbn_core_saved_objects_api_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_api_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server-mocks title: "@kbn/core-saved-objects-api-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server-mocks plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server-mocks'] --- import kbnCoreSavedObjectsApiServerMocksObj from './kbn_core_saved_objects_api_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_base_server_internal.mdx b/api_docs/kbn_core_saved_objects_base_server_internal.mdx index 657a192cfc55b..1e72d58e0a556 100644 --- a/api_docs/kbn_core_saved_objects_base_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_base_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-base-server-internal title: "@kbn/core-saved-objects-base-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-base-server-internal plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-base-server-internal'] --- import kbnCoreSavedObjectsBaseServerInternalObj from './kbn_core_saved_objects_base_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_base_server_mocks.mdx b/api_docs/kbn_core_saved_objects_base_server_mocks.mdx index 0592d99e436a2..6f867a62901a2 100644 --- a/api_docs/kbn_core_saved_objects_base_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_base_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-base-server-mocks title: "@kbn/core-saved-objects-base-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-base-server-mocks plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-base-server-mocks'] --- import kbnCoreSavedObjectsBaseServerMocksObj from './kbn_core_saved_objects_base_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser.mdx b/api_docs/kbn_core_saved_objects_browser.mdx index f567258505107..33a128967a46d 100644 --- a/api_docs/kbn_core_saved_objects_browser.mdx +++ b/api_docs/kbn_core_saved_objects_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser title: "@kbn/core-saved-objects-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser'] --- import kbnCoreSavedObjectsBrowserObj from './kbn_core_saved_objects_browser.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser_internal.mdx b/api_docs/kbn_core_saved_objects_browser_internal.mdx index 684c65ca2ae4a..98178770059a6 100644 --- a/api_docs/kbn_core_saved_objects_browser_internal.mdx +++ b/api_docs/kbn_core_saved_objects_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-internal title: "@kbn/core-saved-objects-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-internal plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser-internal'] --- import kbnCoreSavedObjectsBrowserInternalObj from './kbn_core_saved_objects_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser_mocks.mdx b/api_docs/kbn_core_saved_objects_browser_mocks.mdx index d085d8ad06e5f..66e6af2710803 100644 --- a/api_docs/kbn_core_saved_objects_browser_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-mocks title: "@kbn/core-saved-objects-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-mocks plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser-mocks'] --- import kbnCoreSavedObjectsBrowserMocksObj from './kbn_core_saved_objects_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_common.mdx b/api_docs/kbn_core_saved_objects_common.mdx index 070ebcf0a442d..72a69255a2478 100644 --- a/api_docs/kbn_core_saved_objects_common.mdx +++ b/api_docs/kbn_core_saved_objects_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-common title: "@kbn/core-saved-objects-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-common plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-common'] --- import kbnCoreSavedObjectsCommonObj from './kbn_core_saved_objects_common.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx b/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx index 7a8767012f33a..b96736028b554 100644 --- a/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-import-export-server-internal title: "@kbn/core-saved-objects-import-export-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-import-export-server-internal plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-import-export-server-internal'] --- import kbnCoreSavedObjectsImportExportServerInternalObj from './kbn_core_saved_objects_import_export_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx b/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx index 4875e1285c5b2..7706b9720bfec 100644 --- a/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-import-export-server-mocks title: "@kbn/core-saved-objects-import-export-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-import-export-server-mocks plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-import-export-server-mocks'] --- import kbnCoreSavedObjectsImportExportServerMocksObj from './kbn_core_saved_objects_import_export_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_migration_server_internal.mdx b/api_docs/kbn_core_saved_objects_migration_server_internal.mdx index 4ccfb8be33872..bec825971fcce 100644 --- a/api_docs/kbn_core_saved_objects_migration_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_migration_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-migration-server-internal title: "@kbn/core-saved-objects-migration-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-migration-server-internal plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-migration-server-internal'] --- import kbnCoreSavedObjectsMigrationServerInternalObj from './kbn_core_saved_objects_migration_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx b/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx index 7837d6e6ea4cc..ce67381f1ac27 100644 --- a/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-migration-server-mocks title: "@kbn/core-saved-objects-migration-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-migration-server-mocks plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-migration-server-mocks'] --- import kbnCoreSavedObjectsMigrationServerMocksObj from './kbn_core_saved_objects_migration_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server.mdx b/api_docs/kbn_core_saved_objects_server.mdx index ec585f05e04f9..1a0c32f9965ef 100644 --- a/api_docs/kbn_core_saved_objects_server.mdx +++ b/api_docs/kbn_core_saved_objects_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server title: "@kbn/core-saved-objects-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server'] --- import kbnCoreSavedObjectsServerObj from './kbn_core_saved_objects_server.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server_internal.mdx b/api_docs/kbn_core_saved_objects_server_internal.mdx index a8b9a01da2c9d..2bad63ca8d86e 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server-internal'] --- import kbnCoreSavedObjectsServerInternalObj from './kbn_core_saved_objects_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server_mocks.mdx b/api_docs/kbn_core_saved_objects_server_mocks.mdx index 416a282da9b3e..c89773c610a38 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-07-17 +date: 2024-07-19 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 ca09f2ced1f1c..10644f4e3298b 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-07-17 +date: 2024-07-19 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 064c6afdf1933..4efd445434c76 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-07-17 +date: 2024-07-19 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 e3455a0afa756..75f370995a9c5 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-07-17 +date: 2024-07-19 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 4fbe9cb5423a4..1b34804065d9b 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-07-17 +date: 2024-07-19 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 ef3a6e28474d9..dad0eb23072db 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-07-17 +date: 2024-07-19 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 ccb3537ad47c7..7ea41c0580aa4 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-07-17 +date: 2024-07-19 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 832d886c954e2..ff91389e957ec 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-07-17 +date: 2024-07-19 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 a4fcd5d717daa..68b69e2f09b03 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-07-17 +date: 2024-07-19 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 6987ddb56e8e8..fbf7632fe4206 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-07-17 +date: 2024-07-19 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 60780df7ce0c1..b7eb54f0abb17 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-07-17 +date: 2024-07-19 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 23cd868b68d8c..9223e20e3e70b 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-07-17 +date: 2024-07-19 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 e35ad98351b45..3d4cde2903936 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-07-17 +date: 2024-07-19 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 05a150bf4a88e..920eed2b05d54 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-07-17 +date: 2024-07-19 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 9ab99fbd7dfbc..e1dbe0d52b602 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-07-17 +date: 2024-07-19 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 1b4d5d66d69f8..77d5b18227c21 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-07-17 +date: 2024-07-19 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 ec05b94b42503..6a19fb8e16ed0 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-07-17 +date: 2024-07-19 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 0fc461b2bd6d9..c56dcbe87c558 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-07-17 +date: 2024-07-19 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 870db1e64c852..51c541225f28a 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-07-17 +date: 2024-07-19 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 dbd1a5eed2ef5..5ff4d405b3778 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-07-17 +date: 2024-07-19 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 78c6d25bf58d9..9eacf28f271cc 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-07-17 +date: 2024-07-19 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 9ab45707d3cc4..f1b5e32cdba82 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-07-17 +date: 2024-07-19 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.devdocs.json b/api_docs/kbn_core_ui_settings_browser.devdocs.json index af8bd418a14ea..6d787e29e3af3 100644 --- a/api_docs/kbn_core_ui_settings_browser.devdocs.json +++ b/api_docs/kbn_core_ui_settings_browser.devdocs.json @@ -605,7 +605,15 @@ "section": "def-common.UiSettingsScope", "text": "UiSettingsScope" }, - " | undefined; order?: number | undefined; name?: string | undefined; category?: string[] | undefined; description?: string | undefined; metric?: { type: string; name: string; } | undefined; optionLabels?: Record | undefined; requiresPageReload?: boolean | undefined; readonly?: boolean | undefined; readonlyMode?: ", + " | undefined; order?: number | undefined; name?: string | undefined; getValue?: ((context?: ", + { + "pluginId": "@kbn/core-ui-settings-common", + "scope": "common", + "docId": "kibKbnCoreUiSettingsCommonPluginApi", + "section": "def-common.GetUiSettingsContext", + "text": "GetUiSettingsContext" + }, + " | undefined) => Promise) | undefined; category?: string[] | undefined; description?: string | undefined; metric?: { type: string; name: string; } | undefined; optionLabels?: Record | undefined; requiresPageReload?: boolean | undefined; readonly?: boolean | undefined; readonlyMode?: ", { "pluginId": "@kbn/core-ui-settings-common", "scope": "common", diff --git a/api_docs/kbn_core_ui_settings_browser.mdx b/api_docs/kbn_core_ui_settings_browser.mdx index 8eb30192529f7..a95e592784db5 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-07-17 +date: 2024-07-19 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 983e14c7a888a..42bbfc7c47854 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-07-17 +date: 2024-07-19 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 b2b596a1f9ddd..b701eff0ccd4c 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-07-17 +date: 2024-07-19 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.devdocs.json b/api_docs/kbn_core_ui_settings_common.devdocs.json index d8506de915d75..28ba7bd34797b 100644 --- a/api_docs/kbn_core_ui_settings_common.devdocs.json +++ b/api_docs/kbn_core_ui_settings_common.devdocs.json @@ -103,6 +103,41 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/core-ui-settings-common", + "id": "def-common.GetUiSettingsContext", + "type": "Interface", + "tags": [], + "label": "GetUiSettingsContext", + "description": [], + "path": "packages/core/ui-settings/core-ui-settings-common/src/ui_settings.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-ui-settings-common", + "id": "def-common.GetUiSettingsContext.request", + "type": "Object", + "tags": [], + "label": "request", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + " | undefined" + ], + "path": "packages/core/ui-settings/core-ui-settings-common/src/ui_settings.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/core-ui-settings-common", "id": "def-common.UiSettingsParams", @@ -158,6 +193,55 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "@kbn/core-ui-settings-common", + "id": "def-common.UiSettingsParams.getValue", + "type": "Function", + "tags": [], + "label": "getValue", + "description": [ + "handler to return the default value asynchronously. Supersedes the `value` prop" + ], + "signature": [ + "((context?: ", + { + "pluginId": "@kbn/core-ui-settings-common", + "scope": "common", + "docId": "kibKbnCoreUiSettingsCommonPluginApi", + "section": "def-common.GetUiSettingsContext", + "text": "GetUiSettingsContext" + }, + " | undefined) => Promise) | undefined" + ], + "path": "packages/core/ui-settings/core-ui-settings-common/src/ui_settings.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-ui-settings-common", + "id": "def-common.UiSettingsParams.getValue.$1", + "type": "Object", + "tags": [], + "label": "context", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-ui-settings-common", + "scope": "common", + "docId": "kibKbnCoreUiSettingsCommonPluginApi", + "section": "def-common.GetUiSettingsContext", + "text": "GetUiSettingsContext" + }, + " | undefined" + ], + "path": "packages/core/ui-settings/core-ui-settings-common/src/ui_settings.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, { "parentPluginId": "@kbn/core-ui-settings-common", "id": "def-common.UiSettingsParams.description", diff --git a/api_docs/kbn_core_ui_settings_common.mdx b/api_docs/kbn_core_ui_settings_common.mdx index 82879d8938588..bed7cd802fc51 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-common'] --- import kbnCoreUiSettingsCommonObj from './kbn_core_ui_settings_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 | |-------------------|-----------|------------------------|-----------------| -| 30 | 0 | 5 | 0 | +| 34 | 0 | 8 | 0 | ## Common diff --git a/api_docs/kbn_core_ui_settings_server.devdocs.json b/api_docs/kbn_core_ui_settings_server.devdocs.json index b75823de22cc1..9e30b6a09d822 100644 --- a/api_docs/kbn_core_ui_settings_server.devdocs.json +++ b/api_docs/kbn_core_ui_settings_server.devdocs.json @@ -69,7 +69,15 @@ "\nRetrieves uiSettings values set by the user with fallbacks to default values if not specified." ], "signature": [ - "(key: string) => Promise" + "(key: string, context?: ", + { + "pluginId": "@kbn/core-ui-settings-common", + "scope": "common", + "docId": "kibKbnCoreUiSettingsCommonPluginApi", + "section": "def-common.GetUiSettingsContext", + "text": "GetUiSettingsContext" + }, + " | undefined) => Promise" ], "path": "packages/core/ui-settings/core-ui-settings-server/src/ui_settings_client.ts", "deprecated": false, @@ -89,6 +97,28 @@ "deprecated": false, "trackAdoption": false, "isRequired": true + }, + { + "parentPluginId": "@kbn/core-ui-settings-server", + "id": "def-common.IUiSettingsClient.get.$2", + "type": "Object", + "tags": [], + "label": "context", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-ui-settings-common", + "scope": "common", + "docId": "kibKbnCoreUiSettingsCommonPluginApi", + "section": "def-common.GetUiSettingsContext", + "text": "GetUiSettingsContext" + }, + " | undefined" + ], + "path": "packages/core/ui-settings/core-ui-settings-server/src/ui_settings_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false } ], "returnComment": [] @@ -103,12 +133,43 @@ "\nRetrieves a set of all uiSettings values set by the user with fallbacks to default values if not specified." ], "signature": [ - "() => Promise>" + "(context?: ", + { + "pluginId": "@kbn/core-ui-settings-common", + "scope": "common", + "docId": "kibKbnCoreUiSettingsCommonPluginApi", + "section": "def-common.GetUiSettingsContext", + "text": "GetUiSettingsContext" + }, + " | undefined) => Promise>" ], "path": "packages/core/ui-settings/core-ui-settings-server/src/ui_settings_client.ts", "deprecated": false, "trackAdoption": false, - "children": [], + "children": [ + { + "parentPluginId": "@kbn/core-ui-settings-server", + "id": "def-common.IUiSettingsClient.getAll.$1", + "type": "Object", + "tags": [], + "label": "context", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-ui-settings-common", + "scope": "common", + "docId": "kibKbnCoreUiSettingsCommonPluginApi", + "section": "def-common.GetUiSettingsContext", + "text": "GetUiSettingsContext" + }, + " | undefined" + ], + "path": "packages/core/ui-settings/core-ui-settings-server/src/ui_settings_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], "returnComment": [] }, { diff --git a/api_docs/kbn_core_ui_settings_server.mdx b/api_docs/kbn_core_ui_settings_server.mdx index 88d2a6d011a1f..3e11200189fca 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server'] --- import kbnCoreUiSettingsServerObj from './kbn_core_ui_settings_server.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 | |-------------------|-----------|------------------------|-----------------| -| 40 | 1 | 22 | 0 | +| 42 | 1 | 24 | 0 | ## Common diff --git a/api_docs/kbn_core_ui_settings_server_internal.mdx b/api_docs/kbn_core_ui_settings_server_internal.mdx index a1e2e824557cf..70eb4a6238741 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-07-17 +date: 2024-07-19 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 d5cb1cfcb19b0..9a60963cf70a7 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-07-17 +date: 2024-07-19 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 6fed6320eb166..974746cad1c99 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-07-17 +date: 2024-07-19 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 00d40ae7b25e8..83f639249cdab 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-07-17 +date: 2024-07-19 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 d15fdcc8c21a0..341d6cb35695c 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-07-17 +date: 2024-07-19 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 2f5ec205cb49c..9b048561bf2c4 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-07-17 +date: 2024-07-19 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 ea56c00db8241..8f4ab29a4aa82 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-07-17 +date: 2024-07-19 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 5b491b6599cbd..754efb0175447 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-07-17 +date: 2024-07-19 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 11c8dbe684cce..f82c76099cc72 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-07-17 +date: 2024-07-19 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 6fc9cc40d76c8..5f48096708f25 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-07-17 +date: 2024-07-19 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 cee59768d0a5d..1b7b189c3f392 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-07-17 +date: 2024-07-19 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 dc56bf9efc2f0..3410fe3af4633 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-07-17 +date: 2024-07-19 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 1baa2d583fe5b..bb8ce15dbccf9 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-07-17 +date: 2024-07-19 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 349156053491d..e0a14e42be7f5 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-07-17 +date: 2024-07-19 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 9d8baae23d356..20433cab0b43d 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-07-17 +date: 2024-07-19 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 6ae852bff385c..4304d66a8f0ee 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-07-17 +date: 2024-07-19 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 b262c4c447cfb..0c0efcf5418fa 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-07-17 +date: 2024-07-19 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 b236d2c5ca900..e52fc7ed56313 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-07-17 +date: 2024-07-19 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 7c3d600c17856..7cc6824125cc6 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-07-17 +date: 2024-07-19 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 09a2859486fe6..dc085350fd68f 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-07-17 +date: 2024-07-19 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 2eb6a2b29390f..c07804fc3267b 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-07-17 +date: 2024-07-19 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 9a3b59038d8fd..66196728eec3f 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-07-17 +date: 2024-07-19 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 9eedc55ab5a49..af30ae1889957 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-07-17 +date: 2024-07-19 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 f0ebcf22602ff..0dcf45f7be9aa 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-07-17 +date: 2024-07-19 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 56eb6dfaf4de3..df910c9554769 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-07-17 +date: 2024-07-19 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 ed47d75b81c75..9f9906e2e0611 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-07-17 +date: 2024-07-19 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 eeeec0ea088f3..62747a034fdca 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-07-17 +date: 2024-07-19 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 603f98869a70b..83f77a9b97950 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-07-17 +date: 2024-07-19 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 c2dbe0bf940b6..1bb7989bd5f91 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-07-17 +date: 2024-07-19 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 699e943c11191..63aeccf266eb5 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-observability'] --- import kbnDeeplinksObservabilityObj from './kbn_deeplinks_observability.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_search.mdx b/api_docs/kbn_deeplinks_search.mdx index e9744a5d35ed5..d4338c853fe7c 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-07-17 +date: 2024-07-19 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 1299efca50148..340af27cceb8c 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-07-17 +date: 2024-07-19 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 870d740e5eebd..768a9fcca710f 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-07-17 +date: 2024-07-19 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 366a63ef5e7eb..9c1901f79eaa7 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-07-17 +date: 2024-07-19 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 ff162c92dd0c7..a40588145d1a4 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-07-17 +date: 2024-07-19 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 5c65ee2cedd56..64d398c284429 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-07-17 +date: 2024-07-19 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 5bde99dc336aa..76f824a9eb688 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-07-17 +date: 2024-07-19 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 63b3aecd452bc..9cafa245f9241 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-07-17 +date: 2024-07-19 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 abe8ed730ff17..34d2c0985b4fc 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-07-17 +date: 2024-07-19 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 b749684912cfd..ba597679eda51 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-07-17 +date: 2024-07-19 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 4f86db34fd07b..4a084dc24a909 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-utils'] --- import kbnDevUtilsObj from './kbn_dev_utils.devdocs.json'; diff --git a/api_docs/kbn_discover_utils.devdocs.json b/api_docs/kbn_discover_utils.devdocs.json index 5dbccb1d08d41..5f7a98bd50a8c 100644 --- a/api_docs/kbn_discover_utils.devdocs.json +++ b/api_docs/kbn_discover_utils.devdocs.json @@ -1397,6 +1397,43 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.LogLevelBadge", + "type": "Function", + "tags": [], + "label": "LogLevelBadge", + "description": [], + "signature": [ + "({ logLevel, fallback, \"data-test-subj\": dataTestSubj, ...badgeProps }: Omit<", + "EuiBadgeProps", + ", \"color\" | \"children\"> & { logLevel: {}; fallback?: React.ReactElement> | undefined; }) => JSX.Element" + ], + "path": "packages/kbn-discover-utils/src/data_types/logs/components/log_level_badge.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.LogLevelBadge.$1", + "type": "CompoundType", + "tags": [], + "label": "{\n logLevel,\n fallback,\n 'data-test-subj': dataTestSubj = 'logLevelBadge',\n ...badgeProps\n}", + "description": [], + "signature": [ + "Omit<", + "EuiBadgeProps", + ", \"color\" | \"children\"> & { logLevel: {}; fallback?: React.ReactElement> | undefined; }" + ], + "path": "packages/kbn-discover-utils/src/data_types/logs/components/log_level_badge.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/discover-utils", "id": "def-common.usePager", diff --git a/api_docs/kbn_discover_utils.mdx b/api_docs/kbn_discover_utils.mdx index 13ea049f87d9d..0416b29f6cd11 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/discover-utils'] --- import kbnDiscoverUtilsObj from './kbn_discover_utils.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 | |-------------------|-----------|------------------------|-----------------| -| 128 | 0 | 102 | 1 | +| 130 | 0 | 104 | 1 | ## Common diff --git a/api_docs/kbn_doc_links.mdx b/api_docs/kbn_doc_links.mdx index 4eb57d2d3d300..60c6469fe52fc 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-07-17 +date: 2024-07-19 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 35b70a5e19fd4..9979d5aabf0d8 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-07-17 +date: 2024-07-19 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 626aa767065fd..ef986cdbf4b54 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-07-17 +date: 2024-07-19 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.devdocs.json b/api_docs/kbn_ebt.devdocs.json index 018b79baf453f..3853010dd6f1b 100644 --- a/api_docs/kbn_ebt.devdocs.json +++ b/api_docs/kbn_ebt.devdocs.json @@ -1879,8 +1879,8 @@ "path": "x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_client.ts" }, { - "plugin": "elasticAssistant", - "path": "x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.ts" + "plugin": "datasetQuality", + "path": "x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_client.ts" }, { "plugin": "elasticAssistant", @@ -1888,7 +1888,7 @@ }, { "plugin": "elasticAssistant", - "path": "x-pack/plugins/elastic_assistant/server/routes/attack_discovery/helpers.ts" + "path": "x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.ts" }, { "plugin": "elasticAssistant", @@ -1904,7 +1904,7 @@ }, { "plugin": "elasticAssistant", - "path": "x-pack/plugins/elastic_assistant/server/routes/helpers.ts" + "path": "x-pack/plugins/elastic_assistant/server/routes/attack_discovery/helpers.ts" }, { "plugin": "elasticAssistant", @@ -2318,6 +2318,14 @@ "plugin": "datasetQuality", "path": "x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_service.test.ts" }, + { + "plugin": "datasetQuality", + "path": "x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "datasetQuality", + "path": "x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_service.test.ts" + }, { "plugin": "infra", "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" diff --git a/api_docs/kbn_ebt.mdx b/api_docs/kbn_ebt.mdx index a0ec2ef2c76f8..f30d2ca30d1f9 100644 --- a/api_docs/kbn_ebt.mdx +++ b/api_docs/kbn_ebt.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ebt title: "@kbn/ebt" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ebt plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ebt'] --- import kbnEbtObj from './kbn_ebt.devdocs.json'; diff --git a/api_docs/kbn_ebt_tools.mdx b/api_docs/kbn_ebt_tools.mdx index fc21b952323d9..30ea7179893b1 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-07-17 +date: 2024-07-19 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 d4235e976d4e7..4b4e92db0b1c4 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-07-17 +date: 2024-07-19 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 82c404b289a94..d754e241638a2 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-07-17 +date: 2024-07-19 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 8c6141e989e29..53091cfc0ee2c 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-07-17 +date: 2024-07-19 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.devdocs.json b/api_docs/kbn_elastic_assistant_common.devdocs.json index 594422ba52ead..08a2a57d5668b 100644 --- a/api_docs/kbn_elastic_assistant_common.devdocs.json +++ b/api_docs/kbn_elastic_assistant_common.devdocs.json @@ -2041,7 +2041,7 @@ "label": "ExecuteConnectorRequestBody", "description": [], "signature": [ - "{ actionTypeId: string; subAction: \"invokeAI\" | \"invokeStream\"; replacements: {} & { [k: string]: string; }; conversationId?: string | undefined; message?: string | undefined; model?: string | undefined; alertsIndexPattern?: string | undefined; allow?: string[] | undefined; allowReplacement?: string[] | undefined; isEnabledKnowledgeBase?: boolean | undefined; isEnabledRAGAlerts?: boolean | undefined; size?: number | undefined; langSmithProject?: string | undefined; langSmithApiKey?: string | undefined; }" + "{ actionTypeId: string; subAction: \"invokeAI\" | \"invokeStream\"; replacements: {} & { [k: string]: string; }; conversationId?: string | undefined; message?: string | undefined; model?: string | undefined; alertsIndexPattern?: string | undefined; allow?: string[] | undefined; allowReplacement?: string[] | undefined; size?: number | undefined; langSmithProject?: string | undefined; langSmithApiKey?: string | undefined; }" ], "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/actions_connector/post_actions_connector_execute_route.gen.ts", "deprecated": false, @@ -2056,7 +2056,7 @@ "label": "ExecuteConnectorRequestBodyInput", "description": [], "signature": [ - "{ actionTypeId: string; subAction: \"invokeAI\" | \"invokeStream\"; replacements: {} & { [k: string]: string; }; conversationId?: string | undefined; message?: string | undefined; model?: string | undefined; alertsIndexPattern?: string | undefined; allow?: string[] | undefined; allowReplacement?: string[] | undefined; isEnabledKnowledgeBase?: boolean | undefined; isEnabledRAGAlerts?: boolean | undefined; size?: number | undefined; langSmithProject?: string | undefined; langSmithApiKey?: string | undefined; }" + "{ actionTypeId: string; subAction: \"invokeAI\" | \"invokeStream\"; replacements: {} & { [k: string]: string; }; conversationId?: string | undefined; message?: string | undefined; model?: string | undefined; alertsIndexPattern?: string | undefined; allow?: string[] | undefined; allowReplacement?: string[] | undefined; size?: number | undefined; langSmithProject?: string | undefined; langSmithApiKey?: string | undefined; }" ], "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/actions_connector/post_actions_connector_execute_route.gen.ts", "deprecated": false, @@ -4366,7 +4366,7 @@ "label": "ExecuteConnectorRequestBody", "description": [], "signature": [ - "Zod.ZodObject<{ conversationId: Zod.ZodOptional; message: Zod.ZodOptional; model: Zod.ZodOptional; subAction: Zod.ZodEnum<[\"invokeAI\", \"invokeStream\"]>; actionTypeId: Zod.ZodString; alertsIndexPattern: Zod.ZodOptional; allow: Zod.ZodOptional>; allowReplacement: Zod.ZodOptional>; isEnabledKnowledgeBase: Zod.ZodOptional; isEnabledRAGAlerts: Zod.ZodOptional; replacements: Zod.ZodObject<{}, \"strip\", Zod.ZodString, Zod.objectOutputType<{}, Zod.ZodString, \"strip\">, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>; size: Zod.ZodOptional; langSmithProject: Zod.ZodOptional; langSmithApiKey: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { actionTypeId: string; subAction: \"invokeAI\" | \"invokeStream\"; replacements: {} & { [k: string]: string; }; conversationId?: string | undefined; message?: string | undefined; model?: string | undefined; alertsIndexPattern?: string | undefined; allow?: string[] | undefined; allowReplacement?: string[] | undefined; isEnabledKnowledgeBase?: boolean | undefined; isEnabledRAGAlerts?: boolean | undefined; size?: number | undefined; langSmithProject?: string | undefined; langSmithApiKey?: string | undefined; }, { actionTypeId: string; subAction: \"invokeAI\" | \"invokeStream\"; replacements: {} & { [k: string]: string; }; conversationId?: string | undefined; message?: string | undefined; model?: string | undefined; alertsIndexPattern?: string | undefined; allow?: string[] | undefined; allowReplacement?: string[] | undefined; isEnabledKnowledgeBase?: boolean | undefined; isEnabledRAGAlerts?: boolean | undefined; size?: number | undefined; langSmithProject?: string | undefined; langSmithApiKey?: string | undefined; }>" + "Zod.ZodObject<{ conversationId: Zod.ZodOptional; message: Zod.ZodOptional; model: Zod.ZodOptional; subAction: Zod.ZodEnum<[\"invokeAI\", \"invokeStream\"]>; actionTypeId: Zod.ZodString; alertsIndexPattern: Zod.ZodOptional; allow: Zod.ZodOptional>; allowReplacement: Zod.ZodOptional>; replacements: Zod.ZodObject<{}, \"strip\", Zod.ZodString, Zod.objectOutputType<{}, Zod.ZodString, \"strip\">, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>; size: Zod.ZodOptional; langSmithProject: Zod.ZodOptional; langSmithApiKey: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { actionTypeId: string; subAction: \"invokeAI\" | \"invokeStream\"; replacements: {} & { [k: string]: string; }; conversationId?: string | undefined; message?: string | undefined; model?: string | undefined; alertsIndexPattern?: string | undefined; allow?: string[] | undefined; allowReplacement?: string[] | undefined; size?: number | undefined; langSmithProject?: string | undefined; langSmithApiKey?: string | undefined; }, { actionTypeId: string; subAction: \"invokeAI\" | \"invokeStream\"; replacements: {} & { [k: string]: string; }; conversationId?: string | undefined; message?: string | undefined; model?: string | undefined; alertsIndexPattern?: string | undefined; allow?: string[] | undefined; allowReplacement?: string[] | undefined; size?: number | undefined; langSmithProject?: string | undefined; langSmithApiKey?: string | undefined; }>" ], "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/actions_connector/post_actions_connector_execute_route.gen.ts", "deprecated": false, diff --git a/api_docs/kbn_elastic_assistant_common.mdx b/api_docs/kbn_elastic_assistant_common.mdx index f00f9fe23f0ad..5251118f8284b 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-assistant-common'] --- import kbnElasticAssistantCommonObj from './kbn_elastic_assistant_common.devdocs.json'; diff --git a/api_docs/kbn_entities_schema.devdocs.json b/api_docs/kbn_entities_schema.devdocs.json index b0ee46640112d..fe419217d0e44 100644 --- a/api_docs/kbn_entities_schema.devdocs.json +++ b/api_docs/kbn_entities_schema.devdocs.json @@ -43,7 +43,7 @@ "label": "EntityDefinition", "description": [], "signature": [ - "{ id: string; type: string; version: string; name: string; history: { interval: moment.Duration; timestampField: string; settings?: { syncField?: string | undefined; syncDelay?: string | undefined; frequency?: string | undefined; } | undefined; }; managed: boolean; indexPatterns: string[]; identityFields: ({ field: string; optional: boolean; } | { field: string; optional: boolean; })[]; displayNameTemplate: string; description?: string | undefined; filter?: string | undefined; metadata?: ({ source: string; destination?: string | undefined; limit?: number | undefined; } | { source: string; destination: string; limit: number; })[] | undefined; metrics?: { name: string; metrics: ({ name: string; field: string; aggregation: ", + "{ id: string; type: string; version: string; name: string; history: { interval: moment.Duration; timestampField: string; settings?: { syncField?: string | undefined; syncDelay?: string | undefined; frequency?: string | undefined; } | undefined; }; managed: boolean; indexPatterns: string[]; identityFields: ({ field: string; optional: boolean; } | { field: string; optional: boolean; })[]; displayNameTemplate: string; description?: string | undefined; filter?: string | undefined; metadata?: ({ destination: string; limit: number; source: string; } | { source: string; destination: string; limit: number; })[] | undefined; metrics?: { name: string; metrics: ({ name: string; field: string; aggregation: ", { "pluginId": "@kbn/entities-schema", "scope": "common", @@ -221,7 +221,7 @@ "label": "entityDefinitionSchema", "description": [], "signature": [ - "Zod.ZodObject<{ id: Zod.ZodString; version: Zod.ZodEffects; name: Zod.ZodString; description: Zod.ZodOptional; type: Zod.ZodString; filter: Zod.ZodOptional; indexPatterns: Zod.ZodArray; identityFields: Zod.ZodArray, Zod.ZodEffects]>, \"many\">; displayNameTemplate: Zod.ZodString; metadata: Zod.ZodOptional; limit: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { source: string; destination?: string | undefined; limit?: number | undefined; }, { source: string; destination?: string | undefined; limit?: number | undefined; }>, Zod.ZodEffects]>, \"many\">>; metrics: Zod.ZodOptional; name: Zod.ZodString; description: Zod.ZodOptional; type: Zod.ZodString; filter: Zod.ZodOptional; indexPatterns: Zod.ZodArray; identityFields: Zod.ZodArray, Zod.ZodEffects]>, \"many\">; displayNameTemplate: Zod.ZodString; metadata: Zod.ZodOptional; limit: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { source: string; destination?: string | undefined; limit?: number | undefined; }, { source: string; destination?: string | undefined; limit?: number | undefined; }>, { destination: string; limit: number; source: string; }, { source: string; destination?: string | undefined; limit?: number | undefined; }>, Zod.ZodEffects]>, \"many\">>; metrics: Zod.ZodOptional, \"many\">>; staticFields: Zod.ZodOptional>; managed: Zod.ZodDefault>; history: Zod.ZodObject<{ timestampField: Zod.ZodString; interval: Zod.ZodEffects, moment.Duration, string>; settings: Zod.ZodOptional; syncDelay: Zod.ZodOptional; frequency: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { syncField?: string | undefined; syncDelay?: string | undefined; frequency?: string | undefined; }, { syncField?: string | undefined; syncDelay?: string | undefined; frequency?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { interval: moment.Duration; timestampField: string; settings?: { syncField?: string | undefined; syncDelay?: string | undefined; frequency?: string | undefined; } | undefined; }, { interval: string; timestampField: string; settings?: { syncField?: string | undefined; syncDelay?: string | undefined; frequency?: string | undefined; } | undefined; }>; latest: Zod.ZodOptional; syncDelay: Zod.ZodOptional; frequency: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { syncField?: string | undefined; syncDelay?: string | undefined; frequency?: string | undefined; }, { syncField?: string | undefined; syncDelay?: string | undefined; frequency?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { settings?: { syncField?: string | undefined; syncDelay?: string | undefined; frequency?: string | undefined; } | undefined; }, { settings?: { syncField?: string | undefined; syncDelay?: string | undefined; frequency?: string | undefined; } | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { id: string; type: string; version: string; name: string; history: { interval: moment.Duration; timestampField: string; settings?: { syncField?: string | undefined; syncDelay?: string | undefined; frequency?: string | undefined; } | undefined; }; managed: boolean; indexPatterns: string[]; identityFields: ({ field: string; optional: boolean; } | { field: string; optional: boolean; })[]; displayNameTemplate: string; description?: string | undefined; filter?: string | undefined; metadata?: ({ source: string; destination?: string | undefined; limit?: number | undefined; } | { source: string; destination: string; limit: number; })[] | undefined; metrics?: { name: string; metrics: ({ name: string; field: string; aggregation: ", + "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }>, \"many\">>; staticFields: Zod.ZodOptional>; managed: Zod.ZodDefault>; history: Zod.ZodObject<{ timestampField: Zod.ZodString; interval: Zod.ZodEffects, moment.Duration, string>; settings: Zod.ZodOptional; syncDelay: Zod.ZodOptional; frequency: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { syncField?: string | undefined; syncDelay?: string | undefined; frequency?: string | undefined; }, { syncField?: string | undefined; syncDelay?: string | undefined; frequency?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { interval: moment.Duration; timestampField: string; settings?: { syncField?: string | undefined; syncDelay?: string | undefined; frequency?: string | undefined; } | undefined; }, { interval: string; timestampField: string; settings?: { syncField?: string | undefined; syncDelay?: string | undefined; frequency?: string | undefined; } | undefined; }>; latest: Zod.ZodOptional; syncDelay: Zod.ZodOptional; frequency: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { syncField?: string | undefined; syncDelay?: string | undefined; frequency?: string | undefined; }, { syncField?: string | undefined; syncDelay?: string | undefined; frequency?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { settings?: { syncField?: string | undefined; syncDelay?: string | undefined; frequency?: string | undefined; } | undefined; }, { settings?: { syncField?: string | undefined; syncDelay?: string | undefined; frequency?: string | undefined; } | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { id: string; type: string; version: string; name: string; history: { interval: moment.Duration; timestampField: string; settings?: { syncField?: string | undefined; syncDelay?: string | undefined; frequency?: string | undefined; } | undefined; }; managed: boolean; indexPatterns: string[]; identityFields: ({ field: string; optional: boolean; } | { field: string; optional: boolean; })[]; displayNameTemplate: string; description?: string | undefined; filter?: string | undefined; metadata?: ({ destination: string; limit: number; source: string; } | { source: string; destination: string; limit: number; })[] | undefined; metrics?: { name: string; metrics: ({ name: string; field: string; aggregation: ", { "pluginId": "@kbn/entities-schema", "scope": "common", @@ -407,7 +407,7 @@ "label": "metadataSchema", "description": [], "signature": [ - "Zod.ZodUnion<[Zod.ZodObject<{ source: Zod.ZodString; destination: Zod.ZodOptional; limit: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { source: string; destination?: string | undefined; limit?: number | undefined; }, { source: string; destination?: string | undefined; limit?: number | undefined; }>, Zod.ZodEffects]>" + "Zod.ZodUnion<[Zod.ZodEffects; limit: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { source: string; destination?: string | undefined; limit?: number | undefined; }, { source: string; destination?: string | undefined; limit?: number | undefined; }>, { destination: string; limit: number; source: string; }, { source: string; destination?: string | undefined; limit?: number | undefined; }>, Zod.ZodEffects]>" ], "path": "x-pack/packages/kbn-entities-schema/src/schema/common.ts", "deprecated": false, diff --git a/api_docs/kbn_entities_schema.mdx b/api_docs/kbn_entities_schema.mdx index ad8be8212c94b..699f939e67d43 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-07-17 +date: 2024-07-19 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 f9d41cb5a848d..f3cafb5609db1 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-07-17 +date: 2024-07-19 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 ac9def5715cb8..38be98f82ee53 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-07-17 +date: 2024-07-19 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 12810503887c6..e85ac31fa414f 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-07-17 +date: 2024-07-19 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 7008411ab411e..a03c2d5d463f7 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-07-17 +date: 2024-07-19 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 09998ea2bf973..c2215ea792a13 100644 --- a/api_docs/kbn_es_types.devdocs.json +++ b/api_docs/kbn_es_types.devdocs.json @@ -119,6 +119,20 @@ "path": "packages/kbn-es-types/src/search.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/es-types", + "id": "def-common.ESQLSearchParams.params", + "type": "Array", + "tags": [], + "label": "params", + "description": [], + "signature": [ + "Record[] | undefined" + ], + "path": "packages/kbn-es-types/src/search.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/kbn_es_types.mdx b/api_docs/kbn_es_types.mdx index 0cad2074851e7..96ddd21991d3c 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-types'] --- import kbnEsTypesObj from './kbn_es_types.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 | |-------------------|-----------|------------------------|-----------------| -| 26 | 0 | 26 | 1 | +| 27 | 0 | 27 | 1 | ## Common diff --git a/api_docs/kbn_eslint_plugin_imports.mdx b/api_docs/kbn_eslint_plugin_imports.mdx index a663a43df8216..c4c77bdba76f7 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-07-17 +date: 2024-07-19 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.mdx b/api_docs/kbn_esql_ast.mdx index 63c6c9da36c15..c6edc038f47b8 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/esql-ast'] --- import kbnEsqlAstObj from './kbn_esql_ast.devdocs.json'; diff --git a/api_docs/kbn_esql_utils.devdocs.json b/api_docs/kbn_esql_utils.devdocs.json index ea0d6d6a8f6db..5c0f11f50a144 100644 --- a/api_docs/kbn_esql_utils.devdocs.json +++ b/api_docs/kbn_esql_utils.devdocs.json @@ -160,6 +160,69 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/esql-utils", + "id": "def-common.getEarliestLatestParams", + "type": "Function", + "tags": [], + "label": "getEarliestLatestParams", + "description": [], + "signature": [ + "(query: string, time?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined) => ({ earliest: string; latest?: undefined; } | { latest: string; earliest?: undefined; })[]" + ], + "path": "packages/kbn-esql-utils/src/utils/run_query.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/esql-utils", + "id": "def-common.getEarliestLatestParams.$1", + "type": "string", + "tags": [], + "label": "query", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-esql-utils/src/utils/run_query.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/esql-utils", + "id": "def-common.getEarliestLatestParams.$2", + "type": "Object", + "tags": [], + "label": "time", + "description": [], + "signature": [ + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined" + ], + "path": "packages/kbn-esql-utils/src/utils/run_query.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/esql-utils", "id": "def-common.getESQLAdHocDataview", @@ -168,7 +231,7 @@ "label": "getESQLAdHocDataview", "description": [], "signature": [ - "(indexPattern: string, dataViewsService: ", + "(query: string, dataViewsService: ", { "pluginId": "dataViews", "scope": "public", @@ -195,7 +258,7 @@ "id": "def-common.getESQLAdHocDataview.$1", "type": "string", "tags": [], - "label": "indexPattern", + "label": "query", "description": [], "signature": [ "string" @@ -238,7 +301,7 @@ "label": "getESQLQueryColumns", "description": [], "signature": [ - "({\n esqlQuery,\n search,\n signal,\n}: { esqlQuery: string; search: ", + "({\n esqlQuery,\n search,\n signal,\n timeRange,\n}: { esqlQuery: string; search: ", { "pluginId": "@kbn/search-types", "scope": "common", @@ -246,7 +309,15 @@ "section": "def-common.ISearchGeneric", "text": "ISearchGeneric" }, - "; signal?: AbortSignal | undefined; }) => Promise<", + "; signal?: AbortSignal | undefined; timeRange?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined; }) => Promise<", { "pluginId": "expressions", "scope": "common", @@ -265,7 +336,7 @@ "id": "def-common.getESQLQueryColumns.$1", "type": "Object", "tags": [], - "label": "{\n esqlQuery,\n search,\n signal,\n}", + "label": "{\n esqlQuery,\n search,\n signal,\n timeRange,\n}", "description": [], "path": "packages/kbn-esql-utils/src/utils/run_query.ts", "deprecated": false, @@ -397,6 +468,27 @@ "path": "packages/kbn-esql-utils/src/utils/run_query.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/esql-utils", + "id": "def-common.getESQLQueryColumns.$1.timeRange", + "type": "Object", + "tags": [], + "label": "timeRange", + "description": [], + "signature": [ + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined" + ], + "path": "packages/kbn-esql-utils/src/utils/run_query.ts", + "deprecated": false, + "trackAdoption": false } ] } @@ -412,7 +504,7 @@ "label": "getESQLQueryColumnsRaw", "description": [], "signature": [ - "({\n esqlQuery,\n search,\n signal,\n}: { esqlQuery: string; search: ", + "({\n esqlQuery,\n search,\n signal,\n timeRange,\n}: { esqlQuery: string; search: ", { "pluginId": "@kbn/search-types", "scope": "common", @@ -420,7 +512,15 @@ "section": "def-common.ISearchGeneric", "text": "ISearchGeneric" }, - "; signal?: AbortSignal | undefined; }) => Promise<", + "; signal?: AbortSignal | undefined; timeRange?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined; }) => Promise<", { "pluginId": "@kbn/es-types", "scope": "common", @@ -439,7 +539,7 @@ "id": "def-common.getESQLQueryColumnsRaw.$1", "type": "Object", "tags": [], - "label": "{\n esqlQuery,\n search,\n signal,\n}", + "label": "{\n esqlQuery,\n search,\n signal,\n timeRange,\n}", "description": [], "path": "packages/kbn-esql-utils/src/utils/run_query.ts", "deprecated": false, @@ -571,6 +671,27 @@ "path": "packages/kbn-esql-utils/src/utils/run_query.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/esql-utils", + "id": "def-common.getESQLQueryColumnsRaw.$1.timeRange", + "type": "Object", + "tags": [], + "label": "timeRange", + "description": [], + "signature": [ + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined" + ], + "path": "packages/kbn-esql-utils/src/utils/run_query.ts", + "deprecated": false, + "trackAdoption": false } ] } @@ -586,7 +707,7 @@ "label": "getESQLResults", "description": [], "signature": [ - "({\n esqlQuery,\n search,\n signal,\n filter,\n dropNullColumns,\n}: { esqlQuery: string; search: ", + "({\n esqlQuery,\n search,\n signal,\n filter,\n dropNullColumns,\n timeRange,\n}: { esqlQuery: string; search: ", { "pluginId": "@kbn/search-types", "scope": "common", @@ -594,7 +715,15 @@ "section": "def-common.ISearchGeneric", "text": "ISearchGeneric" }, - "; signal?: AbortSignal | undefined; filter?: unknown; dropNullColumns?: boolean | undefined; }) => Promise<{ response: ", + "; signal?: AbortSignal | undefined; filter?: unknown; dropNullColumns?: boolean | undefined; timeRange?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined; }) => Promise<{ response: ", { "pluginId": "@kbn/es-types", "scope": "common", @@ -621,7 +750,7 @@ "id": "def-common.getESQLResults.$1", "type": "Object", "tags": [], - "label": "{\n esqlQuery,\n search,\n signal,\n filter,\n dropNullColumns,\n}", + "label": "{\n esqlQuery,\n search,\n signal,\n filter,\n dropNullColumns,\n timeRange,\n}", "description": [], "path": "packages/kbn-esql-utils/src/utils/run_query.ts", "deprecated": false, @@ -781,6 +910,27 @@ "path": "packages/kbn-esql-utils/src/utils/run_query.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/esql-utils", + "id": "def-common.getESQLResults.$1.timeRange", + "type": "Object", + "tags": [], + "label": "timeRange", + "description": [], + "signature": [ + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined" + ], + "path": "packages/kbn-esql-utils/src/utils/run_query.ts", + "deprecated": false, + "trackAdoption": false } ] } @@ -1000,6 +1150,78 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/esql-utils", + "id": "def-common.getTimeFieldFromESQLQuery", + "type": "Function", + "tags": [], + "label": "getTimeFieldFromESQLQuery", + "description": [ + "\nWhen the ?earliest and ?latest params are used, we want to retrieve the timefield from the query." + ], + "signature": [ + "(esql: string) => string | undefined" + ], + "path": "packages/kbn-esql-utils/src/utils/query_parsing_helpers.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/esql-utils", + "id": "def-common.getTimeFieldFromESQLQuery.$1", + "type": "string", + "tags": [], + "label": "esql", + "description": [ + ":string" + ], + "signature": [ + "string" + ], + "path": "packages/kbn-esql-utils/src/utils/query_parsing_helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [ + "string" + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/esql-utils", + "id": "def-common.hasEarliestLatestParams", + "type": "Function", + "tags": [], + "label": "hasEarliestLatestParams", + "description": [], + "signature": [ + "(query: string) => boolean" + ], + "path": "packages/kbn-esql-utils/src/utils/run_query.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/esql-utils", + "id": "def-common.hasEarliestLatestParams.$1", + "type": "string", + "tags": [], + "label": "query", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-esql-utils/src/utils/run_query.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/esql-utils", "id": "def-common.hasTransformationalCommand", diff --git a/api_docs/kbn_esql_utils.mdx b/api_docs/kbn_esql_utils.mdx index c690494c68443..06de0eae250bf 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/esql-utils'] --- import kbnEsqlUtilsObj from './kbn_esql_utils.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 | |-------------------|-----------|------------------------|-----------------| -| 53 | 0 | 51 | 0 | +| 63 | 0 | 59 | 0 | ## Common diff --git a/api_docs/kbn_esql_validation_autocomplete.mdx b/api_docs/kbn_esql_validation_autocomplete.mdx index 969d0a2a8ae76..2441662bac33d 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-07-17 +date: 2024-07-19 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 3f2ec126b6ad0..382c6aea11b50 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-07-17 +date: 2024-07-19 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 1ed02b8807e66..ef7f23e14180d 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-07-17 +date: 2024-07-19 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 3b9214fea9c5d..6c6b7220375f5 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-07-17 +date: 2024-07-19 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 ffcbffa82813e..72a1397e28acc 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-types'] --- import kbnFieldTypesObj from './kbn_field_types.devdocs.json'; diff --git a/api_docs/kbn_field_utils.devdocs.json b/api_docs/kbn_field_utils.devdocs.json index 540633131b699..ed7709116eb80 100644 --- a/api_docs/kbn_field_utils.devdocs.json +++ b/api_docs/kbn_field_utils.devdocs.json @@ -85,7 +85,7 @@ "label": "FieldDescription", "description": [], "signature": [ - "({ field, color, truncate, }: React.PropsWithChildren<", + "({ fieldsMetadataService, ...props }: React.PropsWithChildren<", { "pluginId": "@kbn/field-utils", "scope": "common", @@ -93,7 +93,7 @@ "section": "def-common.FieldDescriptionProps", "text": "FieldDescriptionProps" }, - ">) => JSX.Element | null" + ">) => JSX.Element" ], "path": "packages/kbn-field-utils/src/components/field_description/field_description.tsx", "deprecated": false, @@ -104,7 +104,7 @@ "id": "def-common.FieldDescription.$1", "type": "CompoundType", "tags": [], - "label": "{\n field,\n color,\n truncate = true,\n}", + "label": "{\n fieldsMetadataService,\n ...props\n}", "description": [], "signature": [ "React.PropsWithChildren<", @@ -752,47 +752,37 @@ "tags": [], "label": "FieldDescriptionProps", "description": [], + "signature": [ + { + "pluginId": "@kbn/field-utils", + "scope": "common", + "docId": "kibKbnFieldUtilsPluginApi", + "section": "def-common.FieldDescriptionProps", + "text": "FieldDescriptionProps" + }, + " extends ", + "FieldDescriptionContentProps" + ], "path": "packages/kbn-field-utils/src/components/field_description/field_description.tsx", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "@kbn/field-utils", - "id": "def-common.FieldDescriptionProps.field", + "id": "def-common.FieldDescriptionProps.fieldsMetadataService", "type": "Object", "tags": [], - "label": "field", - "description": [], - "signature": [ - "{ name: string; customDescription?: string | undefined; }" - ], - "path": "packages/kbn-field-utils/src/components/field_description/field_description.tsx", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/field-utils", - "id": "def-common.FieldDescriptionProps.color", - "type": "string", - "tags": [], - "label": "color", - "description": [], - "signature": [ - "\"subdued\" | undefined" - ], - "path": "packages/kbn-field-utils/src/components/field_description/field_description.tsx", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/field-utils", - "id": "def-common.FieldDescriptionProps.truncate", - "type": "CompoundType", - "tags": [], - "label": "truncate", + "label": "fieldsMetadataService", "description": [], "signature": [ - "boolean | undefined" + { + "pluginId": "fieldsMetadata", + "scope": "public", + "docId": "kibFieldsMetadataPluginApi", + "section": "def-public.FieldsMetadataPublicStart", + "text": "FieldsMetadataPublicStart" + }, + " | undefined" ], "path": "packages/kbn-field-utils/src/components/field_description/field_description.tsx", "deprecated": false, diff --git a/api_docs/kbn_field_utils.mdx b/api_docs/kbn_field_utils.mdx index 7541cd734862f..445a8e8f21fa7 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-utils'] --- import kbnFieldUtilsObj from './kbn_field_utils.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 | |-------------------|-----------|------------------------|-----------------| -| 51 | 0 | 42 | 1 | +| 49 | 0 | 40 | 2 | ## Common diff --git a/api_docs/kbn_find_used_node_modules.mdx b/api_docs/kbn_find_used_node_modules.mdx index 42f563016d992..7f2cc65a3aceb 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-07-17 +date: 2024-07-19 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 fa038c670c6f3..2a134a0cdcf82 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/formatters'] --- import kbnFormattersObj from './kbn_formatters.devdocs.json'; diff --git a/api_docs/kbn_ftr_common_functional_services.mdx b/api_docs/kbn_ftr_common_functional_services.mdx index 3d3e3cf2395ec..1eca42d709eeb 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-07-17 +date: 2024-07-19 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 c5ad71c0e1ec8..182e1b2230f81 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-07-17 +date: 2024-07-19 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 0b72b1f703cfd..ead0ab19a0059 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-07-17 +date: 2024-07-19 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 96624ab6db4f2..f13c7db6fcf85 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-07-17 +date: 2024-07-19 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 af7c35e6553ee..1122a2ce2cb31 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-csv'] --- import kbnGenerateCsvObj from './kbn_generate_csv.devdocs.json'; diff --git a/api_docs/kbn_grouping.mdx b/api_docs/kbn_grouping.mdx index 5496c99330126..d795d81e30790 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-07-17 +date: 2024-07-19 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 35af97b27d9e3..051e1595d1369 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-07-17 +date: 2024-07-19 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 50dd3c270da3a..131dcbb77ff84 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-07-17 +date: 2024-07-19 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 b2fcd3e121491..1e9b76e1eeebc 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-07-17 +date: 2024-07-19 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 a2d4fbacdaaa2..6711514061f34 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-07-17 +date: 2024-07-19 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 cdfdaab6d9f72..dca782b7b96d9 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-07-17 +date: 2024-07-19 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 09d998f5054a2..45dab8721b663 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-07-17 +date: 2024-07-19 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 180f66191ed35..39228de9db311 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-07-17 +date: 2024-07-19 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 27c8dad861485..8c7c89aa88038 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-07-17 +date: 2024-07-19 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 e667ab32b39ae..0e5b65450f54d 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/import-resolver'] --- import kbnImportResolverObj from './kbn_import_resolver.devdocs.json'; diff --git a/api_docs/kbn_index_management.mdx b/api_docs/kbn_index_management.mdx index 50333536dd793..6f296f3c6003c 100644 --- a/api_docs/kbn_index_management.mdx +++ b/api_docs/kbn_index_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-index-management title: "@kbn/index-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/index-management plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/index-management'] --- import kbnIndexManagementObj from './kbn_index_management.devdocs.json'; diff --git a/api_docs/kbn_inference_integration_flyout.mdx b/api_docs/kbn_inference_integration_flyout.mdx index 8436597508270..fe5bdd938d4a0 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-07-17 +date: 2024-07-19 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 a522c2bbf1bed..7c423788eae5e 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-07-17 +date: 2024-07-19 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 31a8a05771628..6bc8072e863f7 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/interpreter'] --- import kbnInterpreterObj from './kbn_interpreter.devdocs.json'; diff --git a/api_docs/kbn_io_ts_utils.mdx b/api_docs/kbn_io_ts_utils.mdx index e3fe16390b22e..c6a50af27561f 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-07-17 +date: 2024-07-19 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 3e2d089ef87c3..6b49695d6a97e 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ipynb'] --- import kbnIpynbObj from './kbn_ipynb.devdocs.json'; diff --git a/api_docs/kbn_jest_serializers.mdx b/api_docs/kbn_jest_serializers.mdx index 14661db1d7e64..36710c1ce6b3b 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/jest-serializers'] --- import kbnJestSerializersObj from './kbn_jest_serializers.devdocs.json'; diff --git a/api_docs/kbn_journeys.devdocs.json b/api_docs/kbn_journeys.devdocs.json index 41f6843945731..b38a6d1c83525 100644 --- a/api_docs/kbn_journeys.devdocs.json +++ b/api_docs/kbn_journeys.devdocs.json @@ -680,6 +680,22 @@ "trackAdoption": false, "children": [], "returnComment": [] + }, + { + "parentPluginId": "@kbn/journeys", + "id": "def-common.JourneyConfig.takeScreenshotOnSuccess", + "type": "Function", + "tags": [], + "label": "takeScreenshotOnSuccess", + "description": [], + "signature": [ + "() => boolean" + ], + "path": "packages/kbn-journeys/journey/journey_config.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] } ], "initialIsOpen": false diff --git a/api_docs/kbn_journeys.mdx b/api_docs/kbn_journeys.mdx index 766c479a01d97..7c774355154da 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/journeys'] --- import kbnJourneysObj from './kbn_journeys.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 | |-------------------|-----------|------------------------|-----------------| -| 86 | 0 | 78 | 6 | +| 87 | 0 | 79 | 6 | ## Common diff --git a/api_docs/kbn_json_ast.mdx b/api_docs/kbn_json_ast.mdx index 12c1ac620c73a..ef5ab52281ea6 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-07-17 +date: 2024-07-19 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 afc8c70e6a184..fa0ffd7c63330 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/json-schemas'] --- import kbnJsonSchemasObj from './kbn_json_schemas.devdocs.json'; diff --git a/api_docs/kbn_kibana_manifest_schema.mdx b/api_docs/kbn_kibana_manifest_schema.mdx index 94a33a650219b..3ed7bfbb77ac4 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/kibana-manifest-schema'] --- import kbnKibanaManifestSchemaObj from './kbn_kibana_manifest_schema.devdocs.json'; diff --git a/api_docs/kbn_language_documentation_popover.mdx b/api_docs/kbn_language_documentation_popover.mdx index 4154a2beadcb6..1370fb1a0a342 100644 --- a/api_docs/kbn_language_documentation_popover.mdx +++ b/api_docs/kbn_language_documentation_popover.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-language-documentation-popover title: "@kbn/language-documentation-popover" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/language-documentation-popover plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/language-documentation-popover'] --- import kbnLanguageDocumentationPopoverObj from './kbn_language_documentation_popover.devdocs.json'; diff --git a/api_docs/kbn_lens_embeddable_utils.mdx b/api_docs/kbn_lens_embeddable_utils.mdx index 8f448cdc1d813..31b32d045e700 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-07-17 +date: 2024-07-19 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 35dca82410990..06dd963572649 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-07-17 +date: 2024-07-19 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 6e17e9205d61e..f523982a29cf5 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-07-17 +date: 2024-07-19 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 b0795b67c6e54..9accd239d2216 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-07-17 +date: 2024-07-19 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 4858caa8879e0..7343f351fbb99 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-07-17 +date: 2024-07-19 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 bddc9d117e392..8e7a46249c4db 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-07-17 +date: 2024-07-19 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 8168be63da630..180dedc16f7db 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-07-17 +date: 2024-07-19 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 e0e73be1319f8..97eee4621ff16 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-07-17 +date: 2024-07-19 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 9bef8dc81c618..54d80ac87b49e 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-07-17 +date: 2024-07-19 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 c98cc1c8fd32d..8bb71859df9a5 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-07-17 +date: 2024-07-19 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 407461228a73b..a7609dd1bb722 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-07-17 +date: 2024-07-19 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 667188520e5cf..5a2e63da44689 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-07-17 +date: 2024-07-19 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 7388aa1517f75..81d778a86a588 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-field-definition'] --- import kbnManagementSettingsFieldDefinitionObj from './kbn_management_settings_field_definition.devdocs.json'; diff --git a/api_docs/kbn_management_settings_ids.mdx b/api_docs/kbn_management_settings_ids.mdx index 80ac2a71530d0..53e40716f3b1d 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-ids'] --- import kbnManagementSettingsIdsObj from './kbn_management_settings_ids.devdocs.json'; diff --git a/api_docs/kbn_management_settings_section_registry.mdx b/api_docs/kbn_management_settings_section_registry.mdx index f58a5815de873..44fa39945a43a 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-07-17 +date: 2024-07-19 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 425c3b9f7caaf..ab5fc668fc44b 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-07-17 +date: 2024-07-19 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 4baf76d6879e8..9cbff3d9e466e 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-07-17 +date: 2024-07-19 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 96bf810d10121..d351aa9589eed 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-storybook-config'] --- import kbnManagementStorybookConfigObj from './kbn_management_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_mapbox_gl.mdx b/api_docs/kbn_mapbox_gl.mdx index 55c3fdabb6545..7bd768f86215b 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-07-17 +date: 2024-07-19 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 765d68c6eed97..d0c02ef6f851d 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-07-17 +date: 2024-07-19 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 a1cf0d630b0b8..a2db1d9854a16 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-07-17 +date: 2024-07-19 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 2a16bce57828c..1dfd44d071f34 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-07-17 +date: 2024-07-19 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 bdbb914d2bfd4..81f3bb7421ff6 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-07-17 +date: 2024-07-19 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 5d47dca17fc12..c93a71a263f68 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-07-17 +date: 2024-07-19 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 47b96f73c5604..fa1b4aec37925 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-07-17 +date: 2024-07-19 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 c930558f8c3f4..a5be0bb5f4371 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-07-17 +date: 2024-07-19 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 0bb4250b093dc..9eef54428537d 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-07-17 +date: 2024-07-19 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 2967b7215f172..b7571b71eaf25 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-07-17 +date: 2024-07-19 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 85f6425c9727d..ddfd6d6b85d62 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-07-17 +date: 2024-07-19 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 b58812f42f8e9..9e0a904b5d73d 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-07-17 +date: 2024-07-19 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_in_memory_table.mdx b/api_docs/kbn_ml_in_memory_table.mdx index 088e580e8c29d..e4ab364f3caf1 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-07-17 +date: 2024-07-19 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 6f125c8d08413..c9af89981d360 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-07-17 +date: 2024-07-19 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 c256bea9d93a3..b5072e7ddab26 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-07-17 +date: 2024-07-19 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 e053253c14028..84328f6636a24 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-07-17 +date: 2024-07-19 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 a34467853c967..801b940314420 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-07-17 +date: 2024-07-19 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 cd4898af36caa..f1fda85738516 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-07-17 +date: 2024-07-19 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 f9de55d1b318e..d04fac6291c2d 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-number-utils'] --- import kbnMlNumberUtilsObj from './kbn_ml_number_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_query_utils.mdx b/api_docs/kbn_ml_query_utils.mdx index 35718b288b044..e4b9f6577187e 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-07-17 +date: 2024-07-19 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 a0cc88572addf..881a7208a8391 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-07-17 +date: 2024-07-19 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 5dd071cfa1bb8..5451b0f0efa6d 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-07-17 +date: 2024-07-19 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 fca269b4d5964..9594cb2cb50a0 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-07-17 +date: 2024-07-19 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 e8c9a472b01ac..2464e8864a6e3 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-07-17 +date: 2024-07-19 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 b271d3eb1f838..3d975ddfdf1e0 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-07-17 +date: 2024-07-19 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 887ebe67caa00..8ca50dadebc15 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-07-17 +date: 2024-07-19 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 3f7ffbd327eba..2aaecc1ce211f 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-07-17 +date: 2024-07-19 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 e9b5ef2f4e700..885f792015988 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-url-state'] --- import kbnMlUrlStateObj from './kbn_ml_url_state.devdocs.json'; diff --git a/api_docs/kbn_mock_idp_utils.mdx b/api_docs/kbn_mock_idp_utils.mdx index 68bfe93cdb0de..ab6d2646ab124 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-07-17 +date: 2024-07-19 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 cc16eb541f6fa..55f7cd5c7059d 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-07-17 +date: 2024-07-19 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 4bb9f7a0c0fbe..41ba9c23638f4 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/object-versioning'] --- import kbnObjectVersioningObj from './kbn_object_versioning.devdocs.json'; diff --git a/api_docs/kbn_observability_alert_details.mdx b/api_docs/kbn_observability_alert_details.mdx index 3b97ef6e4751c..a161bd4bda1fe 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-07-17 +date: 2024-07-19 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_test_data.mdx b/api_docs/kbn_observability_alerting_test_data.mdx index 3550f30fcce63..0fde5dcadb1a8 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-07-17 +date: 2024-07-19 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 257b145a68454..bf9c40f8f6b3a 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-07-17 +date: 2024-07-19 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_openapi_bundler.mdx b/api_docs/kbn_openapi_bundler.mdx index 25ef7c938b025..033c5d2544baa 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-07-17 +date: 2024-07-19 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 3a8fcdb51029b..2d2f3f7505d84 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-07-17 +date: 2024-07-19 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 ba251bf666758..fdb8929920443 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-07-17 +date: 2024-07-19 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 6d24758c22e56..2eef64fe9b927 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-07-17 +date: 2024-07-19 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 75963901e2631..a098e8baf289c 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-07-17 +date: 2024-07-19 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 12f2a6dc1e616..098480eb6b33b 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-07-17 +date: 2024-07-19 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 858cc3533f25c..326d0a3dfd580 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-07-17 +date: 2024-07-19 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 64fe4ca3fb55e..d5f6185f8824d 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-07-17 +date: 2024-07-19 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 650571074755f..35496c211e2f2 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-07-17 +date: 2024-07-19 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 9d43ffe9ce11b..5655b94dc2d4c 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-07-17 +date: 2024-07-19 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 c07d641e10ed0..9f71d51d810ca 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-07-17 +date: 2024-07-19 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 62e3dbdbba651..bfcc4860d5d79 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/presentation-publishing'] --- import kbnPresentationPublishingObj from './kbn_presentation_publishing.devdocs.json'; diff --git a/api_docs/kbn_profiling_utils.mdx b/api_docs/kbn_profiling_utils.mdx index 3756482780c7f..6aaae6f360049 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-07-17 +date: 2024-07-19 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 9b9a002d827bb..5aa0dcc31fa8a 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-07-17 +date: 2024-07-19 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 9e23c1170d601..77f47778f255a 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-07-17 +date: 2024-07-19 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 1572f79c49d88..c6b75d47d2ffe 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-07-17 +date: 2024-07-19 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 5ba3972ca99fd..082508fb87c18 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-07-17 +date: 2024-07-19 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 0244f237a7091..756efab10ecd7 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-07-17 +date: 2024-07-19 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 1ca6d5c484d97..e957aea62e313 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-07-17 +date: 2024-07-19 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 8c3128878e094..e43d2e9c86065 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-07-17 +date: 2024-07-19 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 c8fc28ac4a0d8..b29301339caa7 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-07-17 +date: 2024-07-19 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 b496e14c59715..517d0ba58ad19 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-07-17 +date: 2024-07-19 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 dd0217fda0f7f..317fd77cfbd39 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-07-17 +date: 2024-07-19 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 e71a5faab4963..d93f5471e3de7 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-07-17 +date: 2024-07-19 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 6f13ab3455c21..fd5848faef2cc 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-07-17 +date: 2024-07-19 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 e53360ece7588..0322f1d39a1c3 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-07-17 +date: 2024-07-19 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 707126f5a2a2f..1126643a4662f 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-source-classifier'] --- import kbnRepoSourceClassifierObj from './kbn_repo_source_classifier.devdocs.json'; diff --git a/api_docs/kbn_reporting_common.mdx b/api_docs/kbn_reporting_common.mdx index 083ce18bb46ef..96475b8ba1ec2 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-common'] --- import kbnReportingCommonObj from './kbn_reporting_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_csv_share_panel.mdx b/api_docs/kbn_reporting_csv_share_panel.mdx index d9c7563715251..b89074409d097 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-csv-share-panel'] --- import kbnReportingCsvSharePanelObj from './kbn_reporting_csv_share_panel.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_csv.mdx b/api_docs/kbn_reporting_export_types_csv.mdx index d3c8f5dcf7da4..ce4601bdd4b1d 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-csv'] --- import kbnReportingExportTypesCsvObj from './kbn_reporting_export_types_csv.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_csv_common.mdx b/api_docs/kbn_reporting_export_types_csv_common.mdx index b5084dde5c8f9..bdbb09aaa4114 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-csv-common'] --- import kbnReportingExportTypesCsvCommonObj from './kbn_reporting_export_types_csv_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_pdf.mdx b/api_docs/kbn_reporting_export_types_pdf.mdx index 591ba3ddc8261..b72ae51049d42 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-07-17 +date: 2024-07-19 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 c05fd9089914c..419bdddfb3098 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-07-17 +date: 2024-07-19 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 c9cf62f4b20ca..8f8bf788532a8 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-07-17 +date: 2024-07-19 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 1fb22215500d6..14d6088878b8a 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-07-17 +date: 2024-07-19 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 fa2d19434be77..b881d8cb8218b 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-mocks-server'] --- import kbnReportingMocksServerObj from './kbn_reporting_mocks_server.devdocs.json'; diff --git a/api_docs/kbn_reporting_public.mdx b/api_docs/kbn_reporting_public.mdx index 3a3510a717ba3..24f7b3ccde3bf 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-public'] --- import kbnReportingPublicObj from './kbn_reporting_public.devdocs.json'; diff --git a/api_docs/kbn_reporting_server.mdx b/api_docs/kbn_reporting_server.mdx index 42ee7d9f5e728..d8ba6c42991c0 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-07-17 +date: 2024-07-19 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 200f2292f2d3e..58ce6be2fb02c 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-07-17 +date: 2024-07-19 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 b6343fae95603..b24fb4f79b037 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-07-17 +date: 2024-07-19 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_rison.mdx b/api_docs/kbn_rison.mdx index ce1a3f435130b..31d265fb0ed05 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-07-17 +date: 2024-07-19 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 2b58bfdd81a52..7eaddbcf7935b 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-07-17 +date: 2024-07-19 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 2aad92e193844..85eca5a8f563c 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-07-17 +date: 2024-07-19 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 af5fc057f3c5c..af9b1254af35d 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-07-17 +date: 2024-07-19 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 aad03970113af..1361721bd2e13 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-07-17 +date: 2024-07-19 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 36d9598a5c163..24474ddceacc1 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-07-17 +date: 2024-07-19 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 a760f17ae5bb0..208ca0ec7a24f 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/saved-objects-settings'] --- import kbnSavedObjectsSettingsObj from './kbn_saved_objects_settings.devdocs.json'; diff --git a/api_docs/kbn_search_api_panels.devdocs.json b/api_docs/kbn_search_api_panels.devdocs.json index 60f8ab7069ab2..4c1fc873dd1be 100644 --- a/api_docs/kbn_search_api_panels.devdocs.json +++ b/api_docs/kbn_search_api_panels.devdocs.json @@ -293,7 +293,7 @@ "label": "GithubLink", "description": [], "signature": [ - "({ assetBasePath, label, href }: React.PropsWithChildren<{ assetBasePath: string; label: string; href: string; }>) => JSX.Element" + "({ assetBasePath, label, href, \"aria-label\": ariaLabel }: React.PropsWithChildren<{ assetBasePath: string; label: string; href: string; 'aria-label'?: string | undefined; }>) => JSX.Element" ], "path": "packages/kbn-search-api-panels/components/github_link.tsx", "deprecated": false, @@ -304,10 +304,10 @@ "id": "def-common.GithubLink.$1", "type": "CompoundType", "tags": [], - "label": "{ assetBasePath, label, href }", + "label": "{ assetBasePath, label, href, 'aria-label': ariaLabel }", "description": [], "signature": [ - "React.PropsWithChildren<{ assetBasePath: string; label: string; href: string; }>" + "React.PropsWithChildren<{ assetBasePath: string; label: string; href: string; 'aria-label'?: string | undefined; }>" ], "path": "packages/kbn-search-api-panels/components/github_link.tsx", "deprecated": false, diff --git a/api_docs/kbn_search_api_panels.mdx b/api_docs/kbn_search_api_panels.mdx index 9a30f18b27d89..ba0eab1946e3e 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-07-17 +date: 2024-07-19 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 d99fdba6e9359..ea85b2828cc34 100644 --- a/api_docs/kbn_search_connectors.devdocs.json +++ b/api_docs/kbn_search_connectors.devdocs.json @@ -51479,6 +51479,2376 @@ } ] }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server", + "type": "Object", + "tags": [], + "label": "sharepoint_server", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration", + "type": "Object", + "tags": [], + "label": "configuration", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.username", + "type": "Object", + "tags": [], + "label": "username", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.username.default_value", + "type": "Uncategorized", + "tags": [], + "label": "default_value", + "description": [], + "signature": [ + "null" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.username.depends_on", + "type": "Array", + "tags": [], + "label": "depends_on", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.username.display", + "type": "string", + "tags": [], + "label": "display", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.DisplayType", + "text": "DisplayType" + }, + ".TEXTBOX" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.username.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.username.options", + "type": "Array", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.username.order", + "type": "number", + "tags": [], + "label": "order", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.username.required", + "type": "boolean", + "tags": [], + "label": "required", + "description": [], + "signature": [ + "true" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.username.sensitive", + "type": "boolean", + "tags": [], + "label": "sensitive", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.username.tooltip", + "type": "string", + "tags": [], + "label": "tooltip", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.username.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.FieldType", + "text": "FieldType" + }, + ".STRING" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.username.ui_restrictions", + "type": "Array", + "tags": [], + "label": "ui_restrictions", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.username.validations", + "type": "Array", + "tags": [], + "label": "validations", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.username.value", + "type": "string", + "tags": [], + "label": "value", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.password", + "type": "Object", + "tags": [], + "label": "password", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.password.default_value", + "type": "Uncategorized", + "tags": [], + "label": "default_value", + "description": [], + "signature": [ + "null" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.password.depends_on", + "type": "Array", + "tags": [], + "label": "depends_on", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.password.display", + "type": "string", + "tags": [], + "label": "display", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.DisplayType", + "text": "DisplayType" + }, + ".TEXTBOX" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.password.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.password.options", + "type": "Array", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.password.order", + "type": "number", + "tags": [], + "label": "order", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.password.required", + "type": "boolean", + "tags": [], + "label": "required", + "description": [], + "signature": [ + "true" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.password.sensitive", + "type": "boolean", + "tags": [], + "label": "sensitive", + "description": [], + "signature": [ + "true" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.password.tooltip", + "type": "string", + "tags": [], + "label": "tooltip", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.password.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.FieldType", + "text": "FieldType" + }, + ".STRING" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.password.ui_restrictions", + "type": "Array", + "tags": [], + "label": "ui_restrictions", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.password.validations", + "type": "Array", + "tags": [], + "label": "validations", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.password.value", + "type": "string", + "tags": [], + "label": "value", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.host_url", + "type": "Object", + "tags": [], + "label": "host_url", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.host_url.default_value", + "type": "Uncategorized", + "tags": [], + "label": "default_value", + "description": [], + "signature": [ + "null" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.host_url.depends_on", + "type": "Array", + "tags": [], + "label": "depends_on", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.host_url.display", + "type": "string", + "tags": [], + "label": "display", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.DisplayType", + "text": "DisplayType" + }, + ".TEXTBOX" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.host_url.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.host_url.options", + "type": "Array", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.host_url.order", + "type": "number", + "tags": [], + "label": "order", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.host_url.required", + "type": "boolean", + "tags": [], + "label": "required", + "description": [], + "signature": [ + "true" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.host_url.sensitive", + "type": "boolean", + "tags": [], + "label": "sensitive", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.host_url.tooltip", + "type": "string", + "tags": [], + "label": "tooltip", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.host_url.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.FieldType", + "text": "FieldType" + }, + ".STRING" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.host_url.ui_restrictions", + "type": "Array", + "tags": [], + "label": "ui_restrictions", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.host_url.validations", + "type": "Array", + "tags": [], + "label": "validations", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.host_url.value", + "type": "string", + "tags": [], + "label": "value", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.site_collections", + "type": "Object", + "tags": [], + "label": "site_collections", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.site_collections.default_value", + "type": "Uncategorized", + "tags": [], + "label": "default_value", + "description": [], + "signature": [ + "null" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.site_collections.depends_on", + "type": "Array", + "tags": [], + "label": "depends_on", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.site_collections.display", + "type": "string", + "tags": [], + "label": "display", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.DisplayType", + "text": "DisplayType" + }, + ".TEXTAREA" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.site_collections.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.site_collections.options", + "type": "Array", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.site_collections.order", + "type": "number", + "tags": [], + "label": "order", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.site_collections.required", + "type": "boolean", + "tags": [], + "label": "required", + "description": [], + "signature": [ + "true" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.site_collections.sensitive", + "type": "boolean", + "tags": [], + "label": "sensitive", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.site_collections.tooltip", + "type": "string", + "tags": [], + "label": "tooltip", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.site_collections.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.FieldType", + "text": "FieldType" + }, + ".LIST" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.site_collections.ui_restrictions", + "type": "Array", + "tags": [], + "label": "ui_restrictions", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.site_collections.validations", + "type": "Array", + "tags": [], + "label": "validations", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.site_collections.value", + "type": "string", + "tags": [], + "label": "value", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.ssl_enabled", + "type": "Object", + "tags": [], + "label": "ssl_enabled", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.ssl_enabled.default_value", + "type": "Uncategorized", + "tags": [], + "label": "default_value", + "description": [], + "signature": [ + "null" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.ssl_enabled.depends_on", + "type": "Array", + "tags": [], + "label": "depends_on", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.ssl_enabled.display", + "type": "string", + "tags": [], + "label": "display", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.DisplayType", + "text": "DisplayType" + }, + ".TOGGLE" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.ssl_enabled.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.ssl_enabled.options", + "type": "Array", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.ssl_enabled.order", + "type": "number", + "tags": [], + "label": "order", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.ssl_enabled.required", + "type": "boolean", + "tags": [], + "label": "required", + "description": [], + "signature": [ + "true" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.ssl_enabled.sensitive", + "type": "boolean", + "tags": [], + "label": "sensitive", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.ssl_enabled.tooltip", + "type": "Uncategorized", + "tags": [], + "label": "tooltip", + "description": [], + "signature": [ + "null" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.ssl_enabled.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.FieldType", + "text": "FieldType" + }, + ".BOOLEAN" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.ssl_enabled.ui_restrictions", + "type": "Array", + "tags": [], + "label": "ui_restrictions", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.ssl_enabled.validations", + "type": "Array", + "tags": [], + "label": "validations", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.ssl_enabled.value", + "type": "boolean", + "tags": [], + "label": "value", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.ssl_ca", + "type": "Object", + "tags": [], + "label": "ssl_ca", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.ssl_ca.default_value", + "type": "Uncategorized", + "tags": [], + "label": "default_value", + "description": [], + "signature": [ + "null" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.ssl_ca.depends_on", + "type": "Array", + "tags": [], + "label": "depends_on", + "description": [], + "signature": [ + "{ field: string; value: true; }[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.ssl_ca.display", + "type": "string", + "tags": [], + "label": "display", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.DisplayType", + "text": "DisplayType" + }, + ".TEXTBOX" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.ssl_ca.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.ssl_ca.options", + "type": "Array", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.ssl_ca.order", + "type": "number", + "tags": [], + "label": "order", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.ssl_ca.required", + "type": "boolean", + "tags": [], + "label": "required", + "description": [], + "signature": [ + "true" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.ssl_ca.sensitive", + "type": "boolean", + "tags": [], + "label": "sensitive", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.ssl_ca.tooltip", + "type": "Uncategorized", + "tags": [], + "label": "tooltip", + "description": [], + "signature": [ + "null" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.ssl_ca.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.FieldType", + "text": "FieldType" + }, + ".STRING" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.ssl_ca.ui_restrictions", + "type": "Array", + "tags": [], + "label": "ui_restrictions", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.ssl_ca.validations", + "type": "Array", + "tags": [], + "label": "validations", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.ssl_ca.value", + "type": "string", + "tags": [], + "label": "value", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.retry_count", + "type": "Object", + "tags": [], + "label": "retry_count", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.retry_count.default_value", + "type": "number", + "tags": [], + "label": "default_value", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.retry_count.depends_on", + "type": "Array", + "tags": [], + "label": "depends_on", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.retry_count.display", + "type": "string", + "tags": [], + "label": "display", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.DisplayType", + "text": "DisplayType" + }, + ".NUMERIC" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.retry_count.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.retry_count.options", + "type": "Array", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.retry_count.order", + "type": "number", + "tags": [], + "label": "order", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.retry_count.required", + "type": "boolean", + "tags": [], + "label": "required", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.retry_count.sensitive", + "type": "boolean", + "tags": [], + "label": "sensitive", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.retry_count.tooltip", + "type": "Uncategorized", + "tags": [], + "label": "tooltip", + "description": [], + "signature": [ + "null" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.retry_count.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.FieldType", + "text": "FieldType" + }, + ".INTEGER" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.retry_count.ui_restrictions", + "type": "Array", + "tags": [], + "label": "ui_restrictions", + "description": [], + "signature": [ + "string[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.retry_count.validations", + "type": "Array", + "tags": [], + "label": "validations", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.retry_count.value", + "type": "number", + "tags": [], + "label": "value", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.use_text_extraction_service", + "type": "Object", + "tags": [], + "label": "use_text_extraction_service", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.use_text_extraction_service.default_value", + "type": "Uncategorized", + "tags": [], + "label": "default_value", + "description": [], + "signature": [ + "null" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.use_text_extraction_service.depends_on", + "type": "Array", + "tags": [], + "label": "depends_on", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.use_text_extraction_service.display", + "type": "string", + "tags": [], + "label": "display", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.DisplayType", + "text": "DisplayType" + }, + ".TOGGLE" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.use_text_extraction_service.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.use_text_extraction_service.options", + "type": "Array", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.use_text_extraction_service.order", + "type": "number", + "tags": [], + "label": "order", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.use_text_extraction_service.required", + "type": "boolean", + "tags": [], + "label": "required", + "description": [], + "signature": [ + "true" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.use_text_extraction_service.sensitive", + "type": "boolean", + "tags": [], + "label": "sensitive", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.use_text_extraction_service.tooltip", + "type": "string", + "tags": [], + "label": "tooltip", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.use_text_extraction_service.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.FieldType", + "text": "FieldType" + }, + ".BOOLEAN" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.use_text_extraction_service.ui_restrictions", + "type": "Array", + "tags": [], + "label": "ui_restrictions", + "description": [], + "signature": [ + "string[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.use_text_extraction_service.validations", + "type": "Array", + "tags": [], + "label": "validations", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.use_text_extraction_service.value", + "type": "boolean", + "tags": [], + "label": "value", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.use_document_level_security", + "type": "Object", + "tags": [], + "label": "use_document_level_security", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.use_document_level_security.default_value", + "type": "Uncategorized", + "tags": [], + "label": "default_value", + "description": [], + "signature": [ + "null" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.use_document_level_security.depends_on", + "type": "Array", + "tags": [], + "label": "depends_on", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.use_document_level_security.display", + "type": "string", + "tags": [], + "label": "display", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.DisplayType", + "text": "DisplayType" + }, + ".TOGGLE" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.use_document_level_security.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.use_document_level_security.options", + "type": "Array", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.use_document_level_security.order", + "type": "number", + "tags": [], + "label": "order", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.use_document_level_security.required", + "type": "boolean", + "tags": [], + "label": "required", + "description": [], + "signature": [ + "true" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.use_document_level_security.sensitive", + "type": "boolean", + "tags": [], + "label": "sensitive", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.use_document_level_security.tooltip", + "type": "string", + "tags": [], + "label": "tooltip", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.use_document_level_security.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.FieldType", + "text": "FieldType" + }, + ".BOOLEAN" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.use_document_level_security.ui_restrictions", + "type": "Array", + "tags": [], + "label": "ui_restrictions", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.use_document_level_security.validations", + "type": "Array", + "tags": [], + "label": "validations", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.use_document_level_security.value", + "type": "boolean", + "tags": [], + "label": "value", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.fetch_unique_list_permissions", + "type": "Object", + "tags": [], + "label": "fetch_unique_list_permissions", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.fetch_unique_list_permissions.default_value", + "type": "Uncategorized", + "tags": [], + "label": "default_value", + "description": [], + "signature": [ + "null" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.fetch_unique_list_permissions.depends_on", + "type": "Array", + "tags": [], + "label": "depends_on", + "description": [], + "signature": [ + "{ field: string; value: true; }[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.fetch_unique_list_permissions.display", + "type": "string", + "tags": [], + "label": "display", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.DisplayType", + "text": "DisplayType" + }, + ".TOGGLE" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.fetch_unique_list_permissions.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.fetch_unique_list_permissions.options", + "type": "Array", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.fetch_unique_list_permissions.order", + "type": "number", + "tags": [], + "label": "order", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.fetch_unique_list_permissions.required", + "type": "boolean", + "tags": [], + "label": "required", + "description": [], + "signature": [ + "true" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.fetch_unique_list_permissions.sensitive", + "type": "boolean", + "tags": [], + "label": "sensitive", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.fetch_unique_list_permissions.tooltip", + "type": "string", + "tags": [], + "label": "tooltip", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.fetch_unique_list_permissions.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.FieldType", + "text": "FieldType" + }, + ".BOOLEAN" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.fetch_unique_list_permissions.ui_restrictions", + "type": "Array", + "tags": [], + "label": "ui_restrictions", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.fetch_unique_list_permissions.validations", + "type": "Array", + "tags": [], + "label": "validations", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.fetch_unique_list_permissions.value", + "type": "boolean", + "tags": [], + "label": "value", + "description": [], + "signature": [ + "true" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.fetch_unique_list_item_permissions", + "type": "Object", + "tags": [], + "label": "fetch_unique_list_item_permissions", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.fetch_unique_list_item_permissions.default_value", + "type": "Uncategorized", + "tags": [], + "label": "default_value", + "description": [], + "signature": [ + "null" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.fetch_unique_list_item_permissions.depends_on", + "type": "Array", + "tags": [], + "label": "depends_on", + "description": [], + "signature": [ + "{ field: string; value: true; }[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.fetch_unique_list_item_permissions.display", + "type": "string", + "tags": [], + "label": "display", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.DisplayType", + "text": "DisplayType" + }, + ".TOGGLE" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.fetch_unique_list_item_permissions.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.fetch_unique_list_item_permissions.options", + "type": "Array", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.fetch_unique_list_item_permissions.order", + "type": "number", + "tags": [], + "label": "order", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.fetch_unique_list_item_permissions.required", + "type": "boolean", + "tags": [], + "label": "required", + "description": [], + "signature": [ + "true" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.fetch_unique_list_item_permissions.sensitive", + "type": "boolean", + "tags": [], + "label": "sensitive", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.fetch_unique_list_item_permissions.tooltip", + "type": "string", + "tags": [], + "label": "tooltip", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.fetch_unique_list_item_permissions.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.FieldType", + "text": "FieldType" + }, + ".BOOLEAN" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.fetch_unique_list_item_permissions.ui_restrictions", + "type": "Array", + "tags": [], + "label": "ui_restrictions", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.fetch_unique_list_item_permissions.validations", + "type": "Array", + "tags": [], + "label": "validations", + "description": [], + "signature": [ + "never[]" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.configuration.fetch_unique_list_item_permissions.value", + "type": "boolean", + "tags": [], + "label": "value", + "description": [], + "signature": [ + "true" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + } + ] + } + ] + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.features", + "type": "Object", + "tags": [], + "label": "features", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.features.FeatureName.SYNC_RULES", + "type": "Object", + "tags": [], + "label": "[FeatureName.SYNC_RULES]", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.features.FeatureName.SYNC_RULES.advanced", + "type": "Object", + "tags": [], + "label": "advanced", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.features.FeatureName.SYNC_RULES.advanced.enabled", + "type": "boolean", + "tags": [], + "label": "enabled", + "description": [], + "signature": [ + "false" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.features.FeatureName.SYNC_RULES.basic", + "type": "Object", + "tags": [], + "label": "basic", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.features.FeatureName.SYNC_RULES.basic.enabled", + "type": "boolean", + "tags": [], + "label": "enabled", + "description": [], + "signature": [ + "true" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + } + ] + } + ] + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.features.FeatureName.DOCUMENT_LEVEL_SECURITY", + "type": "Object", + "tags": [], + "label": "[FeatureName.DOCUMENT_LEVEL_SECURITY]", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.features.FeatureName.DOCUMENT_LEVEL_SECURITY.enabled", + "type": "boolean", + "tags": [], + "label": "enabled", + "description": [], + "signature": [ + "true" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.features.FeatureName.INCREMENTAL_SYNC", + "type": "Object", + "tags": [], + "label": "[FeatureName.INCREMENTAL_SYNC]", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.features.FeatureName.INCREMENTAL_SYNC.enabled", + "type": "boolean", + "tags": [], + "label": "enabled", + "description": [], + "signature": [ + "true" + ], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + } + ] + } + ] + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.name", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.serviceType", + "type": "string", + "tags": [], + "label": "serviceType", + "description": [], + "path": "packages/kbn-search-connectors/types/native_connectors.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, { "parentPluginId": "@kbn/search-connectors", "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.slack", diff --git a/api_docs/kbn_search_connectors.mdx b/api_docs/kbn_search_connectors.mdx index 7449826561f43..9178443221245 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-07-17 +date: 2024-07-19 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 | |-------------------|-----------|------------------------|-----------------| -| 3717 | 0 | 3717 | 0 | +| 3885 | 0 | 3885 | 0 | ## Common diff --git a/api_docs/kbn_search_errors.mdx b/api_docs/kbn_search_errors.mdx index 94f732746ecf2..a2620f5332f55 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-07-17 +date: 2024-07-19 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 eea320cd57d3d..dda5af10be4d2 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-07-17 +date: 2024-07-19 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 58117b344d02c..1449359693a68 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-07-17 +date: 2024-07-19 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_types.mdx b/api_docs/kbn_search_types.mdx index 1b94dec969cd3..6c050933a65a3 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-types'] --- import kbnSearchTypesObj from './kbn_search_types.devdocs.json'; diff --git a/api_docs/kbn_security_api_key_management.mdx b/api_docs/kbn_security_api_key_management.mdx index 7692819f2fea0..fe7229b53ff8b 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-07-17 +date: 2024-07-19 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_form_components.mdx b/api_docs/kbn_security_form_components.mdx index 813e50c6c45e5..8d599e6a1bd68 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-07-17 +date: 2024-07-19 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 f6b00428047d1..5e62d80b5e950 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-07-17 +date: 2024-07-19 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 b7e6f9da2addc..5b2f56df10279 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-07-17 +date: 2024-07-19 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 b40431cee125f..ddb9a7970f640 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-plugin-types-public'] --- import kbnSecurityPluginTypesPublicObj from './kbn_security_plugin_types_public.devdocs.json'; diff --git a/api_docs/kbn_security_plugin_types_server.mdx b/api_docs/kbn_security_plugin_types_server.mdx index 2157e0f660ff8..280bb5a344847 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-07-17 +date: 2024-07-19 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_solution_features.mdx b/api_docs/kbn_security_solution_features.mdx index 95090691d94d2..b84f5e38f8d51 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-07-17 +date: 2024-07-19 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 366583618d53e..efe61981eff53 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-07-17 +date: 2024-07-19 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 b72886bb21579..95bb97044a421 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-07-17 +date: 2024-07-19 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 bd79afda74169..8aed392d53cb4 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-storybook-config'] --- import kbnSecuritySolutionStorybookConfigObj from './kbn_security_solution_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_autocomplete.mdx b/api_docs/kbn_securitysolution_autocomplete.mdx index a6a85bc5ecdf9..8e1024271f0b6 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-07-17 +date: 2024-07-19 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.devdocs.json b/api_docs/kbn_securitysolution_data_table.devdocs.json index d859bcdf86855..3b8680b0b684f 100644 --- a/api_docs/kbn_securitysolution_data_table.devdocs.json +++ b/api_docs/kbn_securitysolution_data_table.devdocs.json @@ -643,7 +643,7 @@ ], "signature": [ "{ [x: string]: ", - "ExpandedDetailType", + "ExpandedEventType", " | undefined; }" ], "path": "x-pack/packages/security-solution/data_table/store/data_table/model.ts", @@ -1259,7 +1259,7 @@ " | undefined; type?: string | undefined; })[]; readonly additionalFilters: Record<", "AlertPageFilterType", ", boolean>; readonly itemsPerPage: number; readonly queryFields: string[]; readonly selectAll: boolean; readonly showCheckboxes: boolean; readonly deletedEventIds: string[]; readonly expandedDetail: Partial>; readonly graphEventId?: string | undefined; readonly indexNames: string[]; readonly isSelectAllChecked: boolean; readonly itemsPerPageOptions: number[]; readonly loadingEventIds: string[]; readonly selectedEventIds: Record" + ], + "path": "packages/kbn-triggers-actions-ui-types/action_group_types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/triggers-actions-ui-types", + "id": "def-common.ActionGroupWithMessageVariables.omitMessageVariables", + "type": "CompoundType", + "tags": [], + "label": "omitMessageVariables", + "description": [], + "signature": [ + { + "pluginId": "@kbn/triggers-actions-ui-types", + "scope": "common", + "docId": "kibKbnTriggersActionsUiTypesPluginApi", + "section": "def-common.OmitMessageVariablesType", + "text": "OmitMessageVariablesType" + }, + " | undefined" + ], + "path": "packages/kbn-triggers-actions-ui-types/action_group_types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/triggers-actions-ui-types", + "id": "def-common.ActionGroupWithMessageVariables.defaultActionMessage", + "type": "string", + "tags": [], + "label": "defaultActionMessage", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-triggers-actions-ui-types/action_group_types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/triggers-actions-ui-types", "id": "def-common.RuleType", @@ -137,6 +204,21 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/triggers-actions-ui-types", + "id": "def-common.OmitMessageVariablesType", + "type": "Type", + "tags": [], + "label": "OmitMessageVariablesType", + "description": [], + "signature": [ + "\"all\" | \"keepContext\"" + ], + "path": "packages/kbn-triggers-actions-ui-types/action_group_types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/triggers-actions-ui-types", "id": "def-common.RuleTypeIndex", diff --git a/api_docs/kbn_triggers_actions_ui_types.mdx b/api_docs/kbn_triggers_actions_ui_types.mdx index 193670e79b86b..e236a7943ac6a 100644 --- a/api_docs/kbn_triggers_actions_ui_types.mdx +++ b/api_docs/kbn_triggers_actions_ui_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-triggers-actions-ui-types title: "@kbn/triggers-actions-ui-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/triggers-actions-ui-types plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/triggers-actions-ui-types'] --- import kbnTriggersActionsUiTypesObj from './kbn_triggers_actions_ui_types.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-o | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 11 | 0 | 11 | 0 | +| 15 | 0 | 15 | 0 | ## Common diff --git a/api_docs/kbn_try_in_console.mdx b/api_docs/kbn_try_in_console.mdx index 99665f1549ab5..5dc36b916aa9e 100644 --- a/api_docs/kbn_try_in_console.mdx +++ b/api_docs/kbn_try_in_console.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-try-in-console title: "@kbn/try-in-console" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/try-in-console plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/try-in-console'] --- import kbnTryInConsoleObj from './kbn_try_in_console.devdocs.json'; diff --git a/api_docs/kbn_ts_projects.mdx b/api_docs/kbn_ts_projects.mdx index 82833627bd4c5..aedeae40f0b09 100644 --- a/api_docs/kbn_ts_projects.mdx +++ b/api_docs/kbn_ts_projects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ts-projects title: "@kbn/ts-projects" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ts-projects plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ts-projects'] --- import kbnTsProjectsObj from './kbn_ts_projects.devdocs.json'; diff --git a/api_docs/kbn_typed_react_router_config.mdx b/api_docs/kbn_typed_react_router_config.mdx index 453f3613bdc0e..5f75cb17d0197 100644 --- a/api_docs/kbn_typed_react_router_config.mdx +++ b/api_docs/kbn_typed_react_router_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-typed-react-router-config title: "@kbn/typed-react-router-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/typed-react-router-config plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/typed-react-router-config'] --- import kbnTypedReactRouterConfigObj from './kbn_typed_react_router_config.devdocs.json'; diff --git a/api_docs/kbn_ui_actions_browser.mdx b/api_docs/kbn_ui_actions_browser.mdx index 13b0a07250e32..fe398481d20b7 100644 --- a/api_docs/kbn_ui_actions_browser.mdx +++ b/api_docs/kbn_ui_actions_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-actions-browser title: "@kbn/ui-actions-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-actions-browser plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-actions-browser'] --- import kbnUiActionsBrowserObj from './kbn_ui_actions_browser.devdocs.json'; diff --git a/api_docs/kbn_ui_shared_deps_src.mdx b/api_docs/kbn_ui_shared_deps_src.mdx index 2ed2c3b247dfe..d01b0238ef555 100644 --- a/api_docs/kbn_ui_shared_deps_src.mdx +++ b/api_docs/kbn_ui_shared_deps_src.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-shared-deps-src title: "@kbn/ui-shared-deps-src" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-shared-deps-src plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-shared-deps-src'] --- import kbnUiSharedDepsSrcObj from './kbn_ui_shared_deps_src.devdocs.json'; diff --git a/api_docs/kbn_ui_theme.mdx b/api_docs/kbn_ui_theme.mdx index de6c0c6efda7d..8f7e0a5bd917e 100644 --- a/api_docs/kbn_ui_theme.mdx +++ b/api_docs/kbn_ui_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-theme title: "@kbn/ui-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-theme plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-theme'] --- import kbnUiThemeObj from './kbn_ui_theme.devdocs.json'; diff --git a/api_docs/kbn_unified_data_table.devdocs.json b/api_docs/kbn_unified_data_table.devdocs.json index 72e1333492b3a..f72afa4ba1baf 100644 --- a/api_docs/kbn_unified_data_table.devdocs.json +++ b/api_docs/kbn_unified_data_table.devdocs.json @@ -2562,7 +2562,7 @@ "section": "def-common.DataGridCellValueElementProps", "text": "DataGridCellValueElementProps" }, - ") => React.ReactNode; }" + ") => React.ReactElement>; }" ], "path": "packages/kbn-unified-data-table/src/types.ts", "deprecated": false, diff --git a/api_docs/kbn_unified_data_table.mdx b/api_docs/kbn_unified_data_table.mdx index ecb47fe0071dd..a57839eb9d861 100644 --- a/api_docs/kbn_unified_data_table.mdx +++ b/api_docs/kbn_unified_data_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-data-table title: "@kbn/unified-data-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-data-table plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-data-table'] --- import kbnUnifiedDataTableObj from './kbn_unified_data_table.devdocs.json'; diff --git a/api_docs/kbn_unified_doc_viewer.mdx b/api_docs/kbn_unified_doc_viewer.mdx index 9604302dadae1..039822df49973 100644 --- a/api_docs/kbn_unified_doc_viewer.mdx +++ b/api_docs/kbn_unified_doc_viewer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-doc-viewer title: "@kbn/unified-doc-viewer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-doc-viewer plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-doc-viewer'] --- import kbnUnifiedDocViewerObj from './kbn_unified_doc_viewer.devdocs.json'; diff --git a/api_docs/kbn_unified_field_list.devdocs.json b/api_docs/kbn_unified_field_list.devdocs.json index 66ee3fbfb7d49..b843b8a0da188 100644 --- a/api_docs/kbn_unified_field_list.devdocs.json +++ b/api_docs/kbn_unified_field_list.devdocs.json @@ -391,7 +391,7 @@ "label": "FieldPopoverHeader", "description": [], "signature": [ - "({ field, closePopover, buttonAddFieldToWorkspaceProps, buttonAddFilterProps, buttonEditFieldProps, buttonDeleteFieldProps, onAddFieldToWorkspace, onAddFilter, onEditField, onDeleteField, }: React.PropsWithChildren<", + "({ field, closePopover, buttonAddFieldToWorkspaceProps, buttonAddFilterProps, buttonEditFieldProps, buttonDeleteFieldProps, onAddFieldToWorkspace, onAddFilter, onEditField, onDeleteField, services, }: React.PropsWithChildren<", { "pluginId": "@kbn/unified-field-list", "scope": "common", @@ -410,7 +410,7 @@ "id": "def-common.FieldPopoverHeader.$1", "type": "CompoundType", "tags": [], - "label": "{\n field,\n closePopover,\n buttonAddFieldToWorkspaceProps,\n buttonAddFilterProps,\n buttonEditFieldProps,\n buttonDeleteFieldProps,\n onAddFieldToWorkspace,\n onAddFilter,\n onEditField,\n onDeleteField,\n}", + "label": "{\n field,\n closePopover,\n buttonAddFieldToWorkspaceProps,\n buttonAddFilterProps,\n buttonEditFieldProps,\n buttonDeleteFieldProps,\n onAddFieldToWorkspace,\n onAddFilter,\n onEditField,\n onDeleteField,\n services,\n}", "description": [], "signature": [ "React.PropsWithChildren<", @@ -1591,6 +1591,14 @@ "section": "def-public.UiActionsPublicStart", "text": "UiActionsPublicStart" }, + " | undefined; fieldsMetadata?: ", + { + "pluginId": "fieldsMetadata", + "scope": "public", + "docId": "kibFieldsMetadataPluginApi", + "section": "def-public.FieldsMetadataPublicStart", + "text": "FieldsMetadataPublicStart" + }, " | undefined; } & { dataViewFieldEditor?: ", { "pluginId": "dataViewFieldEditor", @@ -3835,6 +3843,28 @@ } ], "returnComment": [] + }, + { + "parentPluginId": "@kbn/unified-field-list", + "id": "def-common.FieldPopoverHeaderProps.services", + "type": "Object", + "tags": [], + "label": "services", + "description": [], + "signature": [ + "{ fieldsMetadata?: ", + { + "pluginId": "fieldsMetadata", + "scope": "public", + "docId": "kibFieldsMetadataPluginApi", + "section": "def-public.FieldsMetadataPublicStart", + "text": "FieldsMetadataPublicStart" + }, + " | undefined; } | undefined" + ], + "path": "packages/kbn-unified-field-list/src/components/field_popover/field_popover_header.tsx", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -6126,6 +6156,14 @@ "section": "def-public.UiActionsPublicStart", "text": "UiActionsPublicStart" }, + " | undefined; fieldsMetadata?: ", + { + "pluginId": "fieldsMetadata", + "scope": "public", + "docId": "kibFieldsMetadataPluginApi", + "section": "def-public.FieldsMetadataPublicStart", + "text": "FieldsMetadataPublicStart" + }, " | undefined; } & { dataViewFieldEditor?: ", { "pluginId": "dataViewFieldEditor", diff --git a/api_docs/kbn_unified_field_list.mdx b/api_docs/kbn_unified_field_list.mdx index fe49f4c446752..ca046e96225aa 100644 --- a/api_docs/kbn_unified_field_list.mdx +++ b/api_docs/kbn_unified_field_list.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-field-list title: "@kbn/unified-field-list" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-field-list plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-field-list'] --- import kbnUnifiedFieldListObj from './kbn_unified_field_list.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 | |-------------------|-----------|------------------------|-----------------| -| 313 | 0 | 284 | 8 | +| 314 | 0 | 285 | 8 | ## Common diff --git a/api_docs/kbn_unsaved_changes_badge.mdx b/api_docs/kbn_unsaved_changes_badge.mdx index cd3dcf8b541f4..140e113d024d5 100644 --- a/api_docs/kbn_unsaved_changes_badge.mdx +++ b/api_docs/kbn_unsaved_changes_badge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unsaved-changes-badge title: "@kbn/unsaved-changes-badge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unsaved-changes-badge plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unsaved-changes-badge'] --- import kbnUnsavedChangesBadgeObj from './kbn_unsaved_changes_badge.devdocs.json'; diff --git a/api_docs/kbn_unsaved_changes_prompt.mdx b/api_docs/kbn_unsaved_changes_prompt.mdx index f556a42f16526..9c5dfa7679572 100644 --- a/api_docs/kbn_unsaved_changes_prompt.mdx +++ b/api_docs/kbn_unsaved_changes_prompt.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unsaved-changes-prompt title: "@kbn/unsaved-changes-prompt" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unsaved-changes-prompt plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unsaved-changes-prompt'] --- import kbnUnsavedChangesPromptObj from './kbn_unsaved_changes_prompt.devdocs.json'; diff --git a/api_docs/kbn_use_tracked_promise.mdx b/api_docs/kbn_use_tracked_promise.mdx index 748ae58906815..c9b7e337acc25 100644 --- a/api_docs/kbn_use_tracked_promise.mdx +++ b/api_docs/kbn_use_tracked_promise.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-use-tracked-promise title: "@kbn/use-tracked-promise" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/use-tracked-promise plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/use-tracked-promise'] --- import kbnUseTrackedPromiseObj from './kbn_use_tracked_promise.devdocs.json'; diff --git a/api_docs/kbn_user_profile_components.mdx b/api_docs/kbn_user_profile_components.mdx index 3d1876d7160c0..d2f974cc85dc0 100644 --- a/api_docs/kbn_user_profile_components.mdx +++ b/api_docs/kbn_user_profile_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-user-profile-components title: "@kbn/user-profile-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/user-profile-components plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/user-profile-components'] --- import kbnUserProfileComponentsObj from './kbn_user_profile_components.devdocs.json'; diff --git a/api_docs/kbn_utility_types.mdx b/api_docs/kbn_utility_types.mdx index a720a1c5aa8d0..3ce1a34e81d94 100644 --- a/api_docs/kbn_utility_types.mdx +++ b/api_docs/kbn_utility_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types title: "@kbn/utility-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utility-types'] --- import kbnUtilityTypesObj from './kbn_utility_types.devdocs.json'; diff --git a/api_docs/kbn_utility_types_jest.mdx b/api_docs/kbn_utility_types_jest.mdx index 3465b7e1bbe29..504eac9442dd0 100644 --- a/api_docs/kbn_utility_types_jest.mdx +++ b/api_docs/kbn_utility_types_jest.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types-jest title: "@kbn/utility-types-jest" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types-jest plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utility-types-jest'] --- import kbnUtilityTypesJestObj from './kbn_utility_types_jest.devdocs.json'; diff --git a/api_docs/kbn_utils.mdx b/api_docs/kbn_utils.mdx index fea51fba0380e..596b1e12f13e6 100644 --- a/api_docs/kbn_utils.mdx +++ b/api_docs/kbn_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utils title: "@kbn/utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utils plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utils'] --- import kbnUtilsObj from './kbn_utils.devdocs.json'; diff --git a/api_docs/kbn_visualization_ui_components.mdx b/api_docs/kbn_visualization_ui_components.mdx index b29dadfb2cdf2..14f0ed03e5d3f 100644 --- a/api_docs/kbn_visualization_ui_components.mdx +++ b/api_docs/kbn_visualization_ui_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-visualization-ui-components title: "@kbn/visualization-ui-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/visualization-ui-components plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/visualization-ui-components'] --- import kbnVisualizationUiComponentsObj from './kbn_visualization_ui_components.devdocs.json'; diff --git a/api_docs/kbn_visualization_utils.mdx b/api_docs/kbn_visualization_utils.mdx index 575e6ea4b788b..b401d61ec8b3d 100644 --- a/api_docs/kbn_visualization_utils.mdx +++ b/api_docs/kbn_visualization_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-visualization-utils title: "@kbn/visualization-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/visualization-utils plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/visualization-utils'] --- import kbnVisualizationUtilsObj from './kbn_visualization_utils.devdocs.json'; diff --git a/api_docs/kbn_xstate_utils.mdx b/api_docs/kbn_xstate_utils.mdx index 77903c8fad8f0..7b4e7dc4163b3 100644 --- a/api_docs/kbn_xstate_utils.mdx +++ b/api_docs/kbn_xstate_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-xstate-utils title: "@kbn/xstate-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/xstate-utils plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/xstate-utils'] --- import kbnXstateUtilsObj from './kbn_xstate_utils.devdocs.json'; diff --git a/api_docs/kbn_yarn_lock_validator.mdx b/api_docs/kbn_yarn_lock_validator.mdx index f633e5386ede1..158d15b009108 100644 --- a/api_docs/kbn_yarn_lock_validator.mdx +++ b/api_docs/kbn_yarn_lock_validator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-yarn-lock-validator title: "@kbn/yarn-lock-validator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/yarn-lock-validator plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/yarn-lock-validator'] --- import kbnYarnLockValidatorObj from './kbn_yarn_lock_validator.devdocs.json'; diff --git a/api_docs/kbn_zod_helpers.mdx b/api_docs/kbn_zod_helpers.mdx index aa279d35880fb..1bee81da90f85 100644 --- a/api_docs/kbn_zod_helpers.mdx +++ b/api_docs/kbn_zod_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-zod-helpers title: "@kbn/zod-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/zod-helpers plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/zod-helpers'] --- import kbnZodHelpersObj from './kbn_zod_helpers.devdocs.json'; diff --git a/api_docs/kibana_overview.mdx b/api_docs/kibana_overview.mdx index bc7c1f7849654..a00f9724974e3 100644 --- a/api_docs/kibana_overview.mdx +++ b/api_docs/kibana_overview.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaOverview title: "kibanaOverview" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaOverview plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaOverview'] --- import kibanaOverviewObj from './kibana_overview.devdocs.json'; diff --git a/api_docs/kibana_react.mdx b/api_docs/kibana_react.mdx index 380b3e667594d..9bcd2fc4faa35 100644 --- a/api_docs/kibana_react.mdx +++ b/api_docs/kibana_react.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaReact title: "kibanaReact" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaReact plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaReact'] --- import kibanaReactObj from './kibana_react.devdocs.json'; diff --git a/api_docs/kibana_utils.mdx b/api_docs/kibana_utils.mdx index 0dd6e00fae226..889dcfd14e502 100644 --- a/api_docs/kibana_utils.mdx +++ b/api_docs/kibana_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaUtils title: "kibanaUtils" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaUtils plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaUtils'] --- import kibanaUtilsObj from './kibana_utils.devdocs.json'; diff --git a/api_docs/kubernetes_security.mdx b/api_docs/kubernetes_security.mdx index 133a773f902ee..d3b5c1f39fd2d 100644 --- a/api_docs/kubernetes_security.mdx +++ b/api_docs/kubernetes_security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kubernetesSecurity title: "kubernetesSecurity" image: https://source.unsplash.com/400x175/?github description: API docs for the kubernetesSecurity plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kubernetesSecurity'] --- import kubernetesSecurityObj from './kubernetes_security.devdocs.json'; diff --git a/api_docs/lens.mdx b/api_docs/lens.mdx index f1047acc551f3..62bc1104b8422 100644 --- a/api_docs/lens.mdx +++ b/api_docs/lens.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lens title: "lens" image: https://source.unsplash.com/400x175/?github description: API docs for the lens plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lens'] --- import lensObj from './lens.devdocs.json'; diff --git a/api_docs/license_api_guard.mdx b/api_docs/license_api_guard.mdx index ae28664e425d5..dce10beedf00f 100644 --- a/api_docs/license_api_guard.mdx +++ b/api_docs/license_api_guard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseApiGuard title: "licenseApiGuard" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseApiGuard plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licenseApiGuard'] --- import licenseApiGuardObj from './license_api_guard.devdocs.json'; diff --git a/api_docs/license_management.mdx b/api_docs/license_management.mdx index b1586032792da..24f76edefa0a2 100644 --- a/api_docs/license_management.mdx +++ b/api_docs/license_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseManagement title: "licenseManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseManagement plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licenseManagement'] --- import licenseManagementObj from './license_management.devdocs.json'; diff --git a/api_docs/licensing.mdx b/api_docs/licensing.mdx index 33602f1dad70c..acf1e01ca6dfc 100644 --- a/api_docs/licensing.mdx +++ b/api_docs/licensing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licensing title: "licensing" image: https://source.unsplash.com/400x175/?github description: API docs for the licensing plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licensing'] --- import licensingObj from './licensing.devdocs.json'; diff --git a/api_docs/links.mdx b/api_docs/links.mdx index 09aa78ba061cf..90ec03c4e1c66 100644 --- a/api_docs/links.mdx +++ b/api_docs/links.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/links title: "links" image: https://source.unsplash.com/400x175/?github description: API docs for the links plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'links'] --- import linksObj from './links.devdocs.json'; diff --git a/api_docs/lists.mdx b/api_docs/lists.mdx index 91728a5c8794b..d5573fa415985 100644 --- a/api_docs/lists.mdx +++ b/api_docs/lists.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lists title: "lists" image: https://source.unsplash.com/400x175/?github description: API docs for the lists plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lists'] --- import listsObj from './lists.devdocs.json'; diff --git a/api_docs/logs_data_access.mdx b/api_docs/logs_data_access.mdx index bc4bd36392f66..9c462f51bf1f5 100644 --- a/api_docs/logs_data_access.mdx +++ b/api_docs/logs_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/logsDataAccess title: "logsDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the logsDataAccess plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logsDataAccess'] --- import logsDataAccessObj from './logs_data_access.devdocs.json'; diff --git a/api_docs/logs_explorer.mdx b/api_docs/logs_explorer.mdx index 4a02e35ff6bb3..e967ed8fa1da1 100644 --- a/api_docs/logs_explorer.mdx +++ b/api_docs/logs_explorer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/logsExplorer title: "logsExplorer" image: https://source.unsplash.com/400x175/?github description: API docs for the logsExplorer plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logsExplorer'] --- import logsExplorerObj from './logs_explorer.devdocs.json'; diff --git a/api_docs/logs_shared.mdx b/api_docs/logs_shared.mdx index ee13b07d64d71..8c7b1b538d029 100644 --- a/api_docs/logs_shared.mdx +++ b/api_docs/logs_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/logsShared title: "logsShared" image: https://source.unsplash.com/400x175/?github description: API docs for the logsShared plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logsShared'] --- import logsSharedObj from './logs_shared.devdocs.json'; diff --git a/api_docs/management.mdx b/api_docs/management.mdx index 612ffb77201ce..f4fa99fcbe9f4 100644 --- a/api_docs/management.mdx +++ b/api_docs/management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/management title: "management" image: https://source.unsplash.com/400x175/?github description: API docs for the management plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'management'] --- import managementObj from './management.devdocs.json'; diff --git a/api_docs/maps.mdx b/api_docs/maps.mdx index d4d2b44849ab3..19a53f395f13d 100644 --- a/api_docs/maps.mdx +++ b/api_docs/maps.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/maps title: "maps" image: https://source.unsplash.com/400x175/?github description: API docs for the maps plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'maps'] --- import mapsObj from './maps.devdocs.json'; diff --git a/api_docs/maps_ems.mdx b/api_docs/maps_ems.mdx index 8b2d528d77bba..86e528bece172 100644 --- a/api_docs/maps_ems.mdx +++ b/api_docs/maps_ems.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/mapsEms title: "mapsEms" image: https://source.unsplash.com/400x175/?github description: API docs for the mapsEms plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mapsEms'] --- import mapsEmsObj from './maps_ems.devdocs.json'; diff --git a/api_docs/metrics_data_access.mdx b/api_docs/metrics_data_access.mdx index 1101d9dc4cda2..7874d000766f5 100644 --- a/api_docs/metrics_data_access.mdx +++ b/api_docs/metrics_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/metricsDataAccess title: "metricsDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the metricsDataAccess plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'metricsDataAccess'] --- import metricsDataAccessObj from './metrics_data_access.devdocs.json'; diff --git a/api_docs/ml.mdx b/api_docs/ml.mdx index 7390924ce6f6b..ac20b2d277988 100644 --- a/api_docs/ml.mdx +++ b/api_docs/ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ml title: "ml" image: https://source.unsplash.com/400x175/?github description: API docs for the ml plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ml'] --- import mlObj from './ml.devdocs.json'; diff --git a/api_docs/mock_idp_plugin.mdx b/api_docs/mock_idp_plugin.mdx index 81d2cbf8cebd5..a688a9eee0cb7 100644 --- a/api_docs/mock_idp_plugin.mdx +++ b/api_docs/mock_idp_plugin.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/mockIdpPlugin title: "mockIdpPlugin" image: https://source.unsplash.com/400x175/?github description: API docs for the mockIdpPlugin plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mockIdpPlugin'] --- import mockIdpPluginObj from './mock_idp_plugin.devdocs.json'; diff --git a/api_docs/monitoring.mdx b/api_docs/monitoring.mdx index e23269831850f..468efe39a43e8 100644 --- a/api_docs/monitoring.mdx +++ b/api_docs/monitoring.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoring title: "monitoring" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoring plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'monitoring'] --- import monitoringObj from './monitoring.devdocs.json'; diff --git a/api_docs/monitoring_collection.mdx b/api_docs/monitoring_collection.mdx index 886d8a43eb8c3..44d1ddef06d1e 100644 --- a/api_docs/monitoring_collection.mdx +++ b/api_docs/monitoring_collection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoringCollection title: "monitoringCollection" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoringCollection plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'monitoringCollection'] --- import monitoringCollectionObj from './monitoring_collection.devdocs.json'; diff --git a/api_docs/navigation.mdx b/api_docs/navigation.mdx index 60328a1b93238..022e231592d54 100644 --- a/api_docs/navigation.mdx +++ b/api_docs/navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/navigation title: "navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the navigation plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'navigation'] --- import navigationObj from './navigation.devdocs.json'; diff --git a/api_docs/newsfeed.mdx b/api_docs/newsfeed.mdx index 111010f02c6d6..d34eb0612c9d4 100644 --- a/api_docs/newsfeed.mdx +++ b/api_docs/newsfeed.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/newsfeed title: "newsfeed" image: https://source.unsplash.com/400x175/?github description: API docs for the newsfeed plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'newsfeed'] --- import newsfeedObj from './newsfeed.devdocs.json'; diff --git a/api_docs/no_data_page.mdx b/api_docs/no_data_page.mdx index d98caf62253d1..d3d86cc80bd48 100644 --- a/api_docs/no_data_page.mdx +++ b/api_docs/no_data_page.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/noDataPage title: "noDataPage" image: https://source.unsplash.com/400x175/?github description: API docs for the noDataPage plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'noDataPage'] --- import noDataPageObj from './no_data_page.devdocs.json'; diff --git a/api_docs/notifications.mdx b/api_docs/notifications.mdx index f074ccf306d20..6be2f0ae2ab1c 100644 --- a/api_docs/notifications.mdx +++ b/api_docs/notifications.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/notifications title: "notifications" image: https://source.unsplash.com/400x175/?github description: API docs for the notifications plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'notifications'] --- import notificationsObj from './notifications.devdocs.json'; diff --git a/api_docs/observability.mdx b/api_docs/observability.mdx index 85062ac671d2d..19dac849f307f 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observability'] --- import observabilityObj from './observability.devdocs.json'; diff --git a/api_docs/observability_a_i_assistant.mdx b/api_docs/observability_a_i_assistant.mdx index 53b22aae83faa..6ec95242b32ba 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-07-17 +date: 2024-07-19 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 da88d0f7940f1..69991c4bbd3e4 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-07-17 +date: 2024-07-19 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 3b4443ba018bb..0c13c12e3e6f2 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-07-17 +date: 2024-07-19 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 a62b5e4499d67..825db78348d90 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-07-17 +date: 2024-07-19 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 b9e62cd792d12..ee2bde8a0bc16 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-07-17 +date: 2024-07-19 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 6f155064e85d5..88a835e4da69d 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-07-17 +date: 2024-07-19 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 60862df09fd5b..446de54ae73d6 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-07-17 +date: 2024-07-19 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 c98c711cd94b5..a535f327c14e6 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-07-17 +date: 2024-07-19 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 9f4d2afc6429b..566db866b23af 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-07-17 +date: 2024-07-19 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 | |--------------|----------|------------------------| -| 813 | 696 | 42 | +| 814 | 697 | 42 | ### Public API health stats | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 49987 | 239 | 38101 | 1899 | +| 50197 | 239 | 38308 | 1900 | ## Plugin Directory @@ -95,14 +95,14 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds 'shape' function and renderer to expressions | 148 | 0 | 146 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Expression Tagcloud plugin adds a `tagcloud` renderer and function to the expression plugin. The renderer will display the `Wordcloud` chart. | 6 | 0 | 6 | 2 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Expression XY plugin adds a `xy` renderer and function to the expression plugin. The renderer will display the `xy` chart. | 180 | 0 | 169 | 13 | -| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Adds expression runtime to Kibana | 2233 | 17 | 1763 | 6 | +| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Adds expression runtime to Kibana | 2235 | 17 | 1765 | 6 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 247 | 0 | 102 | 2 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Index pattern fields and ambiguous values formatters | 292 | 5 | 253 | 3 | -| | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | Exposes services for async usage and search of fields metadata. | 39 | 0 | 39 | 7 | +| | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | Exposes services for async usage and search of fields metadata. | 42 | 0 | 42 | 7 | | | [@elastic/kibana-gis](https://github.com/orgs/elastic/teams/kibana-gis) | 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. | 84 | 0 | 84 | 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) | - | 1349 | 5 | 1227 | 72 | +| | [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) | - | 1350 | 5 | 1228 | 72 | | 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 | @@ -195,7 +195,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 25 | 0 | 25 | 3 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 10 | 0 | 10 | 0 | | synthetics | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | This plugin visualizes data from Synthetics and Heartbeat, and integrates with other Observability solutions. | 0 | 0 | 0 | 0 | -| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 102 | 0 | 59 | 5 | +| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 103 | 0 | 60 | 5 | | | [@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 | @@ -237,7 +237,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Package name           | Maintaining team | Description | API Cnt | Any Cnt | Missing
comments | Missing
exports | |--------------|----------------|-----------|--------------|----------|---------------|--------| | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 11 | 5 | 11 | 0 | -| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 5 | 0 | 5 | 0 | +| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 14 | 0 | 14 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 36 | 0 | 0 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 2 | 0 | 0 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 54 | 0 | 0 | 0 | @@ -247,7 +247,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 194 | 0 | 191 | 0 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 33 | 0 | 33 | 0 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 22 | 0 | 5 | 1 | -| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 299 | 0 | 283 | 8 | +| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 300 | 0 | 284 | 8 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 73 | 0 | 73 | 2 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 1 | 0 | 0 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 18 | 0 | 18 | 0 | @@ -255,6 +255,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 49 | 0 | 49 | 8 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 192 | 0 | 192 | 30 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 11 | 0 | 11 | 0 | +| | [@elastic/security-defend-workflows](https://github.com/orgs/elastic/teams/security-defend-workflows) | - | 2 | 0 | 2 | 0 | | | [@elastic/kibana-qa](https://github.com/orgs/elastic/teams/kibana-qa) | - | 12 | 0 | 12 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 4 | 0 | 1 | 0 | | | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 10 | 0 | 10 | 0 | @@ -437,8 +438,8 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 33 | 2 | 20 | 1 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 11 | 1 | 11 | 3 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 8 | 0 | 8 | 0 | -| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 30 | 0 | 5 | 0 | -| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 40 | 1 | 22 | 0 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 34 | 0 | 8 | 0 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 42 | 1 | 24 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 20 | 1 | 19 | 3 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 6 | 0 | 6 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 155 | 0 | 144 | 0 | @@ -480,7 +481,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 102 | 0 | 86 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 15 | 0 | 9 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 38 | 2 | 33 | 0 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 128 | 0 | 102 | 1 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 130 | 0 | 104 | 1 | | | [@elastic/docs](https://github.com/orgs/elastic/teams/docs) | - | 78 | 0 | 78 | 2 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 5 | 0 | 5 | 1 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 41 | 0 | 27 | 6 | @@ -495,16 +496,16 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 32 | 0 | 19 | 1 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 11 | 0 | 6 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 269 | 1 | 209 | 15 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 26 | 0 | 26 | 1 | +| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 27 | 0 | 27 | 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) | - | 110 | 1 | 101 | 10 | -| | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 53 | 0 | 51 | 0 | +| | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 63 | 0 | 59 | 0 | | | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 194 | 0 | 183 | 10 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 40 | 0 | 40 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 52 | 0 | 52 | 1 | | | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | - | 39 | 0 | 14 | 1 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 22 | 0 | 18 | 0 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 51 | 0 | 42 | 1 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 49 | 0 | 40 | 2 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 2 | 0 | 0 | 0 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 3 | 0 | 3 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 36 | 0 | 21 | 1 | @@ -529,7 +530,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | - | 60 | 0 | 60 | 4 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 44 | 0 | 44 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 13 | 0 | 13 | 0 | -| | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 86 | 0 | 78 | 6 | +| | [@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) | - | 108 | 0 | 107 | 0 | @@ -634,7 +635,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/security-detections-response](https://github.com/orgs/elastic/teams/security-detections-response) | - | 127 | 0 | 124 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 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) | - | 3717 | 0 | 3717 | 0 | +| | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 3885 | 0 | 3885 | 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) | - | 25 | 0 | 25 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 20 | 0 | 18 | 1 | @@ -728,7 +729,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 33 | 0 | 13 | 0 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 8 | 0 | 8 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 72 | 0 | 55 | 0 | -| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 11 | 0 | 11 | 0 | +| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 15 | 0 | 15 | 0 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 2 | 0 | 2 | 1 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 39 | 0 | 25 | 1 | | | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | - | 86 | 0 | 86 | 1 | @@ -737,7 +738,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@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 | 154 | 0 | 81 | 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 | 313 | 0 | 284 | 8 | +| | [@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 | 314 | 0 | 285 | 8 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 13 | 0 | 9 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 2 | 0 | 2 | 0 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 3 | 0 | 2 | 1 | diff --git a/api_docs/presentation_panel.mdx b/api_docs/presentation_panel.mdx index 9d721b7d1c4ed..b5177c53a9223 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-07-17 +date: 2024-07-19 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 5c8ccc1a235ba..c54ed4557a816 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-07-17 +date: 2024-07-19 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 1ade60b36f6cd..ec8e99128d90d 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-07-17 +date: 2024-07-19 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 3c8f2f7882489..2fd5d45f8dddc 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-07-17 +date: 2024-07-19 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 34f73b93f654b..fae2674dc7ade 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-07-17 +date: 2024-07-19 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 aa7bb221ed945..77eddf150d1da 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-07-17 +date: 2024-07-19 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 8f10611ed41c6..1f20a86386a3c 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'rollup'] --- import rollupObj from './rollup.devdocs.json'; diff --git a/api_docs/rule_registry.devdocs.json b/api_docs/rule_registry.devdocs.json index a08293333c27a..28757d39b23df 100644 --- a/api_docs/rule_registry.devdocs.json +++ b/api_docs/rule_registry.devdocs.json @@ -4253,11 +4253,11 @@ "\nWhen initializing an index, a plugin/solution can provide a custom\nILM policy that will be applied to concrete indices of this index.\n\nNote that policy will be shared between all namespaces of the index." ], "signature": [ - "{ phases: ", - "IlmPhases", - "; _meta?: ", + "{ _meta?: ", "Metadata", - " | undefined; }" + " | undefined; phases: ", + "IlmPhases", + "; }" ], "path": "x-pack/plugins/rule_registry/server/rule_data_plugin_service/index_options.ts", "deprecated": false, diff --git a/api_docs/rule_registry.mdx b/api_docs/rule_registry.mdx index 854a71226647c..c48b9093c7b4f 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-07-17 +date: 2024-07-19 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 33ad81bffd123..92cb0d4dc7a61 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-07-17 +date: 2024-07-19 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 5a7cc212eb2de..3209deb8e6f62 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-07-17 +date: 2024-07-19 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 113304cadc5e2..550a55d6cbb86 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-07-17 +date: 2024-07-19 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 3502791bfbee2..3de2d12b39c27 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-07-17 +date: 2024-07-19 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 84d4dcef25b5a..4f43bcc87b08e 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-07-17 +date: 2024-07-19 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 27039a2acfea2..30d73150d6cad 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-07-17 +date: 2024-07-19 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 1a661078b4359..0d290026add89 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-07-17 +date: 2024-07-19 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 737096e67764c..f93f74eafe7de 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-07-17 +date: 2024-07-19 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 20d093f8ea85a..5f7796e1c200a 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotting'] --- import screenshottingObj from './screenshotting.devdocs.json'; diff --git a/api_docs/search_connectors.mdx b/api_docs/search_connectors.mdx index 5eabe6f340eaa..c915d777081e6 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchConnectors'] --- import searchConnectorsObj from './search_connectors.devdocs.json'; diff --git a/api_docs/search_homepage.mdx b/api_docs/search_homepage.mdx index bd9e322e04433..ab50c32cff1b1 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchHomepage'] --- import searchHomepageObj from './search_homepage.devdocs.json'; diff --git a/api_docs/search_inference_endpoints.mdx b/api_docs/search_inference_endpoints.mdx index 670f78dea3475..2bbded20ab5cc 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-07-17 +date: 2024-07-19 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 0efb3c3636b2f..9a21a4bf580ab 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchNotebooks'] --- import searchNotebooksObj from './search_notebooks.devdocs.json'; diff --git a/api_docs/search_playground.mdx b/api_docs/search_playground.mdx index 67cd77a6b8c4b..86ad57d49e853 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchPlayground'] --- import searchPlaygroundObj from './search_playground.devdocs.json'; diff --git a/api_docs/security.mdx b/api_docs/security.mdx index 34a2745d12b70..a4f1e33c2caaf 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-07-17 +date: 2024-07-19 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 36965aaa5fa96..2bb81ce2378d2 100644 --- a/api_docs/security_solution.devdocs.json +++ b/api_docs/security_solution.devdocs.json @@ -485,7 +485,7 @@ "\nExperimental flag needed to enable the link" ], "signature": [ - "\"assistantKnowledgeBaseByDefault\" | \"assistantModelEvaluation\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionsEnabled\" | \"endpointResponseActionsEnabled\" | \"responseActionUploadEnabled\" | \"automatedProcessActionsEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"responseActionsSentinelOneV2Enabled\" | \"responseActionsSentinelOneGetFileEnabled\" | \"responseActionsSentinelOneKillProcessEnabled\" | \"responseActionsCrowdstrikeManualHostIsolationEnabled\" | \"responseActionScanEnabled\" | \"alertsPageChartsEnabled\" | \"alertTypeEnabled\" | \"securitySolutionNotesEnabled\" | \"entityAlertPreviewEnabled\" | \"newUserDetailsFlyoutManagedUser\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"protectionUpdatesEnabled\" | \"AIAssistantOnRuleCreationFormEnabled\" | \"disableTimelineSaveTour\" | \"alertSuppressionForEsqlRuleEnabled\" | \"riskEnginePrivilegesRouteEnabled\" | \"alertSuppressionForMachineLearningRuleEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"crowdstrikeDataInAnalyzerEnabled\" | \"jamfDataInAnalyzerEnabled\" | \"timelineEsqlTabDisabled\" | \"unifiedComponentsInTimelineDisabled\" | \"analyzerDatePickersAndSourcererDisabled\" | \"prebuiltRulesCustomizationEnabled\" | \"malwareOnWriteScanOptionAvailable\" | \"unifiedManifestEnabled\" | \"valueListItemsModalEnabled\" | \"bulkCustomHighlightedFieldsEnabled\" | \"manualRuleRunEnabled\" | \"filterProcessDescendantsForEventFiltersEnabled\" | undefined" + "\"assistantKnowledgeBaseByDefault\" | \"assistantModelEvaluation\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionsEnabled\" | \"endpointResponseActionsEnabled\" | \"responseActionUploadEnabled\" | \"automatedProcessActionsEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"responseActionsSentinelOneV2Enabled\" | \"responseActionsSentinelOneGetFileEnabled\" | \"responseActionsSentinelOneKillProcessEnabled\" | \"responseActionsSentinelOneProcessesEnabled\" | \"responseActionsCrowdstrikeManualHostIsolationEnabled\" | \"responseActionScanEnabled\" | \"alertsPageChartsEnabled\" | \"alertTypeEnabled\" | \"securitySolutionNotesEnabled\" | \"entityAlertPreviewEnabled\" | \"newUserDetailsFlyoutManagedUser\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"protectionUpdatesEnabled\" | \"AIAssistantOnRuleCreationFormEnabled\" | \"disableTimelineSaveTour\" | \"alertSuppressionForEsqlRuleEnabled\" | \"riskEnginePrivilegesRouteEnabled\" | \"alertSuppressionForMachineLearningRuleEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"crowdstrikeDataInAnalyzerEnabled\" | \"jamfDataInAnalyzerEnabled\" | \"timelineEsqlTabDisabled\" | \"unifiedComponentsInTimelineDisabled\" | \"analyzerDatePickersAndSourcererDisabled\" | \"prebuiltRulesCustomizationEnabled\" | \"malwareOnWriteScanOptionAvailable\" | \"unifiedManifestEnabled\" | \"valueListItemsModalEnabled\" | \"bulkCustomHighlightedFieldsEnabled\" | \"manualRuleRunEnabled\" | \"filterProcessDescendantsForEventFiltersEnabled\" | undefined" ], "path": "x-pack/plugins/security_solution/public/common/links/types.ts", "deprecated": false, @@ -565,7 +565,7 @@ "\nExperimental flag needed to disable the link. Opposite of experimentalKey" ], "signature": [ - "\"assistantKnowledgeBaseByDefault\" | \"assistantModelEvaluation\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionsEnabled\" | \"endpointResponseActionsEnabled\" | \"responseActionUploadEnabled\" | \"automatedProcessActionsEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"responseActionsSentinelOneV2Enabled\" | \"responseActionsSentinelOneGetFileEnabled\" | \"responseActionsSentinelOneKillProcessEnabled\" | \"responseActionsCrowdstrikeManualHostIsolationEnabled\" | \"responseActionScanEnabled\" | \"alertsPageChartsEnabled\" | \"alertTypeEnabled\" | \"securitySolutionNotesEnabled\" | \"entityAlertPreviewEnabled\" | \"newUserDetailsFlyoutManagedUser\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"protectionUpdatesEnabled\" | \"AIAssistantOnRuleCreationFormEnabled\" | \"disableTimelineSaveTour\" | \"alertSuppressionForEsqlRuleEnabled\" | \"riskEnginePrivilegesRouteEnabled\" | \"alertSuppressionForMachineLearningRuleEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"crowdstrikeDataInAnalyzerEnabled\" | \"jamfDataInAnalyzerEnabled\" | \"timelineEsqlTabDisabled\" | \"unifiedComponentsInTimelineDisabled\" | \"analyzerDatePickersAndSourcererDisabled\" | \"prebuiltRulesCustomizationEnabled\" | \"malwareOnWriteScanOptionAvailable\" | \"unifiedManifestEnabled\" | \"valueListItemsModalEnabled\" | \"bulkCustomHighlightedFieldsEnabled\" | \"manualRuleRunEnabled\" | \"filterProcessDescendantsForEventFiltersEnabled\" | undefined" + "\"assistantKnowledgeBaseByDefault\" | \"assistantModelEvaluation\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionsEnabled\" | \"endpointResponseActionsEnabled\" | \"responseActionUploadEnabled\" | \"automatedProcessActionsEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"responseActionsSentinelOneV2Enabled\" | \"responseActionsSentinelOneGetFileEnabled\" | \"responseActionsSentinelOneKillProcessEnabled\" | \"responseActionsSentinelOneProcessesEnabled\" | \"responseActionsCrowdstrikeManualHostIsolationEnabled\" | \"responseActionScanEnabled\" | \"alertsPageChartsEnabled\" | \"alertTypeEnabled\" | \"securitySolutionNotesEnabled\" | \"entityAlertPreviewEnabled\" | \"newUserDetailsFlyoutManagedUser\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"protectionUpdatesEnabled\" | \"AIAssistantOnRuleCreationFormEnabled\" | \"disableTimelineSaveTour\" | \"alertSuppressionForEsqlRuleEnabled\" | \"riskEnginePrivilegesRouteEnabled\" | \"alertSuppressionForMachineLearningRuleEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"crowdstrikeDataInAnalyzerEnabled\" | \"jamfDataInAnalyzerEnabled\" | \"timelineEsqlTabDisabled\" | \"unifiedComponentsInTimelineDisabled\" | \"analyzerDatePickersAndSourcererDisabled\" | \"prebuiltRulesCustomizationEnabled\" | \"malwareOnWriteScanOptionAvailable\" | \"unifiedManifestEnabled\" | \"valueListItemsModalEnabled\" | \"bulkCustomHighlightedFieldsEnabled\" | \"manualRuleRunEnabled\" | \"filterProcessDescendantsForEventFiltersEnabled\" | undefined" ], "path": "x-pack/plugins/security_solution/public/common/links/types.ts", "deprecated": false, @@ -1544,21 +1544,21 @@ ], "signature": [ "{ query?: ", - "ExpandedDetailType", + "ExpandedEventType", " | undefined; graph?: ", - "ExpandedDetailType", + "ExpandedEventType", " | undefined; notes?: ", - "ExpandedDetailType", + "ExpandedEventType", " | undefined; pinned?: ", - "ExpandedDetailType", + "ExpandedEventType", " | undefined; eql?: ", - "ExpandedDetailType", + "ExpandedEventType", " | undefined; session?: ", - "ExpandedDetailType", + "ExpandedEventType", " | undefined; securityAssistant?: ", - "ExpandedDetailType", + "ExpandedEventType", " | undefined; esql?: ", - "ExpandedDetailType", + "ExpandedEventType", " | undefined; }" ], "path": "x-pack/plugins/security_solution/public/timelines/store/model.ts", @@ -1964,7 +1964,7 @@ "label": "experimentalFeatures", "description": [], "signature": [ - "{ readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly automatedProcessActionsEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly responseActionsSentinelOneV2Enabled: boolean; readonly responseActionsSentinelOneGetFileEnabled: boolean; readonly responseActionsSentinelOneKillProcessEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly responseActionScanEnabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly securitySolutionNotesEnabled: boolean; readonly entityAlertPreviewEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly AIAssistantOnRuleCreationFormEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly alertSuppressionForEsqlRuleEnabled: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly alertSuppressionForMachineLearningRuleEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly unifiedComponentsInTimelineDisabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly prebuiltRulesCustomizationEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly valueListItemsModalEnabled: boolean; readonly bulkCustomHighlightedFieldsEnabled: boolean; readonly manualRuleRunEnabled: boolean; readonly filterProcessDescendantsForEventFiltersEnabled: boolean; }" + "{ readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly automatedProcessActionsEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly responseActionsSentinelOneV2Enabled: boolean; readonly responseActionsSentinelOneGetFileEnabled: boolean; readonly responseActionsSentinelOneKillProcessEnabled: boolean; readonly responseActionsSentinelOneProcessesEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly responseActionScanEnabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly securitySolutionNotesEnabled: boolean; readonly entityAlertPreviewEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly AIAssistantOnRuleCreationFormEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly alertSuppressionForEsqlRuleEnabled: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly alertSuppressionForMachineLearningRuleEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly unifiedComponentsInTimelineDisabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly prebuiltRulesCustomizationEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly valueListItemsModalEnabled: boolean; readonly bulkCustomHighlightedFieldsEnabled: boolean; readonly manualRuleRunEnabled: boolean; readonly filterProcessDescendantsForEventFiltersEnabled: boolean; }" ], "path": "x-pack/plugins/security_solution/public/types.ts", "deprecated": false, @@ -3071,7 +3071,7 @@ "\nThe security solution generic experimental features" ], "signature": [ - "{ readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly automatedProcessActionsEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly responseActionsSentinelOneV2Enabled: boolean; readonly responseActionsSentinelOneGetFileEnabled: boolean; readonly responseActionsSentinelOneKillProcessEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly responseActionScanEnabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly securitySolutionNotesEnabled: boolean; readonly entityAlertPreviewEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly AIAssistantOnRuleCreationFormEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly alertSuppressionForEsqlRuleEnabled: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly alertSuppressionForMachineLearningRuleEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly unifiedComponentsInTimelineDisabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly prebuiltRulesCustomizationEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly valueListItemsModalEnabled: boolean; readonly bulkCustomHighlightedFieldsEnabled: boolean; readonly manualRuleRunEnabled: boolean; readonly filterProcessDescendantsForEventFiltersEnabled: boolean; }" + "{ readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly automatedProcessActionsEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly responseActionsSentinelOneV2Enabled: boolean; readonly responseActionsSentinelOneGetFileEnabled: boolean; readonly responseActionsSentinelOneKillProcessEnabled: boolean; readonly responseActionsSentinelOneProcessesEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly responseActionScanEnabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly securitySolutionNotesEnabled: boolean; readonly entityAlertPreviewEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly AIAssistantOnRuleCreationFormEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly alertSuppressionForEsqlRuleEnabled: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly alertSuppressionForMachineLearningRuleEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly unifiedComponentsInTimelineDisabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly prebuiltRulesCustomizationEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly valueListItemsModalEnabled: boolean; readonly bulkCustomHighlightedFieldsEnabled: boolean; readonly manualRuleRunEnabled: boolean; readonly filterProcessDescendantsForEventFiltersEnabled: boolean; }" ], "path": "x-pack/plugins/security_solution/server/plugin_contract.ts", "deprecated": false, @@ -3247,7 +3247,7 @@ "label": "ExperimentalFeatures", "description": [], "signature": [ - "{ readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly automatedProcessActionsEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly responseActionsSentinelOneV2Enabled: boolean; readonly responseActionsSentinelOneGetFileEnabled: boolean; readonly responseActionsSentinelOneKillProcessEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly responseActionScanEnabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly securitySolutionNotesEnabled: boolean; readonly entityAlertPreviewEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly AIAssistantOnRuleCreationFormEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly alertSuppressionForEsqlRuleEnabled: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly alertSuppressionForMachineLearningRuleEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly unifiedComponentsInTimelineDisabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly prebuiltRulesCustomizationEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly valueListItemsModalEnabled: boolean; readonly bulkCustomHighlightedFieldsEnabled: boolean; readonly manualRuleRunEnabled: boolean; readonly filterProcessDescendantsForEventFiltersEnabled: boolean; }" + "{ readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly automatedProcessActionsEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly responseActionsSentinelOneV2Enabled: boolean; readonly responseActionsSentinelOneGetFileEnabled: boolean; readonly responseActionsSentinelOneKillProcessEnabled: boolean; readonly responseActionsSentinelOneProcessesEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly responseActionScanEnabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly securitySolutionNotesEnabled: boolean; readonly entityAlertPreviewEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly AIAssistantOnRuleCreationFormEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly alertSuppressionForEsqlRuleEnabled: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly alertSuppressionForMachineLearningRuleEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly unifiedComponentsInTimelineDisabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly prebuiltRulesCustomizationEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly valueListItemsModalEnabled: boolean; readonly bulkCustomHighlightedFieldsEnabled: boolean; readonly manualRuleRunEnabled: boolean; readonly filterProcessDescendantsForEventFiltersEnabled: boolean; }" ], "path": "x-pack/plugins/security_solution/common/experimental_features.ts", "deprecated": false, @@ -3313,7 +3313,7 @@ "\nA list of allowed values that can be used in `xpack.securitySolution.enableExperimental`.\nThis object is then used to validate and parse the value entered." ], "signature": [ - "{ readonly excludePoliciesInFilterEnabled: false; readonly kubernetesEnabled: true; readonly donutChartEmbeddablesEnabled: false; readonly previewTelemetryUrlEnabled: false; readonly extendedRuleExecutionLoggingEnabled: false; readonly socTrendsEnabled: false; readonly responseActionsEnabled: true; readonly endpointResponseActionsEnabled: true; readonly responseActionUploadEnabled: true; readonly automatedProcessActionsEnabled: true; readonly responseActionsSentinelOneV1Enabled: true; readonly responseActionsSentinelOneV2Enabled: true; readonly responseActionsSentinelOneGetFileEnabled: true; readonly responseActionsSentinelOneKillProcessEnabled: false; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: true; readonly responseActionScanEnabled: false; readonly alertsPageChartsEnabled: true; readonly alertTypeEnabled: false; readonly securitySolutionNotesEnabled: false; readonly entityAlertPreviewEnabled: false; readonly assistantModelEvaluation: false; readonly assistantKnowledgeBaseByDefault: false; readonly newUserDetailsFlyoutManagedUser: false; readonly riskScoringPersistence: true; readonly riskScoringRoutesEnabled: true; readonly esqlRulesDisabled: false; readonly protectionUpdatesEnabled: true; readonly AIAssistantOnRuleCreationFormEnabled: false; readonly disableTimelineSaveTour: false; readonly alertSuppressionForEsqlRuleEnabled: false; readonly riskEnginePrivilegesRouteEnabled: true; readonly alertSuppressionForMachineLearningRuleEnabled: false; readonly sentinelOneDataInAnalyzerEnabled: true; readonly sentinelOneManualHostActionsEnabled: true; readonly crowdstrikeDataInAnalyzerEnabled: true; readonly jamfDataInAnalyzerEnabled: false; readonly timelineEsqlTabDisabled: false; readonly unifiedComponentsInTimelineDisabled: false; readonly analyzerDatePickersAndSourcererDisabled: false; readonly prebuiltRulesCustomizationEnabled: false; readonly malwareOnWriteScanOptionAvailable: true; readonly unifiedManifestEnabled: true; readonly valueListItemsModalEnabled: true; readonly bulkCustomHighlightedFieldsEnabled: false; readonly manualRuleRunEnabled: false; readonly filterProcessDescendantsForEventFiltersEnabled: false; }" + "{ readonly excludePoliciesInFilterEnabled: false; readonly kubernetesEnabled: true; readonly donutChartEmbeddablesEnabled: false; readonly previewTelemetryUrlEnabled: false; readonly extendedRuleExecutionLoggingEnabled: false; readonly socTrendsEnabled: false; readonly responseActionsEnabled: true; readonly endpointResponseActionsEnabled: true; readonly responseActionUploadEnabled: true; readonly automatedProcessActionsEnabled: true; readonly responseActionsSentinelOneV1Enabled: true; readonly responseActionsSentinelOneV2Enabled: true; readonly responseActionsSentinelOneGetFileEnabled: true; readonly responseActionsSentinelOneKillProcessEnabled: false; readonly responseActionsSentinelOneProcessesEnabled: false; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: true; readonly responseActionScanEnabled: false; readonly alertsPageChartsEnabled: true; readonly alertTypeEnabled: false; readonly securitySolutionNotesEnabled: false; readonly entityAlertPreviewEnabled: false; readonly assistantModelEvaluation: false; readonly assistantKnowledgeBaseByDefault: false; readonly newUserDetailsFlyoutManagedUser: false; readonly riskScoringPersistence: true; readonly riskScoringRoutesEnabled: true; readonly esqlRulesDisabled: false; readonly protectionUpdatesEnabled: true; readonly AIAssistantOnRuleCreationFormEnabled: false; readonly disableTimelineSaveTour: false; readonly alertSuppressionForEsqlRuleEnabled: false; readonly riskEnginePrivilegesRouteEnabled: true; readonly alertSuppressionForMachineLearningRuleEnabled: false; readonly sentinelOneDataInAnalyzerEnabled: true; readonly sentinelOneManualHostActionsEnabled: true; readonly crowdstrikeDataInAnalyzerEnabled: true; readonly jamfDataInAnalyzerEnabled: false; readonly timelineEsqlTabDisabled: false; readonly unifiedComponentsInTimelineDisabled: false; readonly analyzerDatePickersAndSourcererDisabled: false; readonly prebuiltRulesCustomizationEnabled: false; readonly malwareOnWriteScanOptionAvailable: true; readonly unifiedManifestEnabled: true; readonly valueListItemsModalEnabled: true; readonly bulkCustomHighlightedFieldsEnabled: false; readonly manualRuleRunEnabled: false; readonly filterProcessDescendantsForEventFiltersEnabled: false; }" ], "path": "x-pack/plugins/security_solution/common/experimental_features.ts", "deprecated": false, diff --git a/api_docs/security_solution.mdx b/api_docs/security_solution.mdx index a30dc5cb9b47c..118b7106482ba 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolution'] --- import securitySolutionObj from './security_solution.devdocs.json'; diff --git a/api_docs/security_solution_ess.mdx b/api_docs/security_solution_ess.mdx index 9edc66bad160e..fc49dd6ea0a43 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-07-17 +date: 2024-07-19 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 1598a83c30847..ffd78717acee6 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-07-17 +date: 2024-07-19 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 787da762cc424..455eb86883543 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-07-17 +date: 2024-07-19 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 2396a331d872b..9bb7bd55ffb66 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-07-17 +date: 2024-07-19 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 3cb6341be95bb..801f8ac8f0f08 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-07-17 +date: 2024-07-19 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 0c58024ec0f5c..60a8ee533aa5e 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-07-17 +date: 2024-07-19 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 60cc8c14ff5c1..fa420b1bd5103 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'share'] --- import shareObj from './share.devdocs.json'; diff --git a/api_docs/slo.devdocs.json b/api_docs/slo.devdocs.json index 033f65c0cbd60..abc6c2ff0d31c 100644 --- a/api_docs/slo.devdocs.json +++ b/api_docs/slo.devdocs.json @@ -1358,8 +1358,8 @@ "pluginId": "features", "scope": "server", "docId": "kibFeaturesPluginApi", - "section": "def-server.PluginSetupContract", - "text": "PluginSetupContract" + "section": "def-server.FeaturesPluginSetup", + "text": "FeaturesPluginSetup" } ], "path": "x-pack/plugins/observability_solution/slo/server/plugin.ts", diff --git a/api_docs/slo.mdx b/api_docs/slo.mdx index d9804b69536c8..67cdd05d7caa9 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-07-17 +date: 2024-07-19 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 8249ff9684bf5..390c3f16da495 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-07-17 +date: 2024-07-19 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 e20e1b9e5b31f..5ee71bfea6c40 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-07-17 +date: 2024-07-19 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 efd1d5318ae93..4d9bd3276cef7 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-07-17 +date: 2024-07-19 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 a9a862236acf8..4a3b68280a11e 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'stackConnectors'] --- import stackConnectorsObj from './stack_connectors.devdocs.json'; diff --git a/api_docs/task_manager.devdocs.json b/api_docs/task_manager.devdocs.json index a0b783aa2c615..0d837238488c8 100644 --- a/api_docs/task_manager.devdocs.json +++ b/api_docs/task_manager.devdocs.json @@ -126,7 +126,15 @@ "section": "def-common.CoreSetup", "text": "CoreSetup" }, - ", plugins: { usageCollection?: ", + "<", + { + "pluginId": "taskManager", + "scope": "server", + "docId": "kibTaskManagerPluginApi", + "section": "def-server.TaskManagerStartContract", + "text": "TaskManagerStartContract" + }, + ", unknown>, plugins: { usageCollection?: ", { "pluginId": "usageCollection", "scope": "server", @@ -162,7 +170,15 @@ "section": "def-common.CoreSetup", "text": "CoreSetup" }, - "" + "<", + { + "pluginId": "taskManager", + "scope": "server", + "docId": "kibTaskManagerPluginApi", + "section": "def-server.TaskManagerStartContract", + "text": "TaskManagerStartContract" + }, + ", unknown>" ], "path": "x-pack/plugins/task_manager/server/plugin.ts", "deprecated": false, @@ -258,6 +274,22 @@ } ], "returnComment": [] + }, + { + "parentPluginId": "taskManager", + "id": "def-server.TaskManagerPlugin.stop", + "type": "Function", + "tags": [], + "label": "stop", + "description": [], + "signature": [ + "() => void" + ], + "path": "x-pack/plugins/task_manager/server/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] } ], "initialIsOpen": false diff --git a/api_docs/task_manager.mdx b/api_docs/task_manager.mdx index 6f28514e0e7a1..72662e79b24ad 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'taskManager'] --- import taskManagerObj from './task_manager.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-o | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 102 | 0 | 59 | 5 | +| 103 | 0 | 60 | 5 | ## Server diff --git a/api_docs/telemetry.mdx b/api_docs/telemetry.mdx index 742af7eee7c8a..e9c2a057f85c6 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-07-17 +date: 2024-07-19 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 272b5f8cabcb6..e8bb66599967d 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryCollectionManager'] --- import telemetryCollectionManagerObj from './telemetry_collection_manager.devdocs.json'; diff --git a/api_docs/telemetry_collection_xpack.mdx b/api_docs/telemetry_collection_xpack.mdx index bcd52289525c7..dfe110bdc27be 100644 --- a/api_docs/telemetry_collection_xpack.mdx +++ b/api_docs/telemetry_collection_xpack.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryCollectionXpack title: "telemetryCollectionXpack" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryCollectionXpack plugin -date: 2024-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryCollectionXpack'] --- import telemetryCollectionXpackObj from './telemetry_collection_xpack.devdocs.json'; diff --git a/api_docs/telemetry_management_section.mdx b/api_docs/telemetry_management_section.mdx index 187e1989bc3fd..12417519c63e2 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-07-17 +date: 2024-07-19 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 262aa3cadf786..5faf7c4a7b752 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'threatIntelligence'] --- import threatIntelligenceObj from './threat_intelligence.devdocs.json'; diff --git a/api_docs/timelines.mdx b/api_docs/timelines.mdx index 3fa0084c8af7c..7c093bb5350f4 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-07-17 +date: 2024-07-19 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 c3249e240752c..074808410a61c 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'transform'] --- import transformObj from './transform.devdocs.json'; diff --git a/api_docs/triggers_actions_ui.devdocs.json b/api_docs/triggers_actions_ui.devdocs.json index 23ad7592bc323..895dc65e64912 100644 --- a/api_docs/triggers_actions_ui.devdocs.json +++ b/api_docs/triggers_actions_ui.devdocs.json @@ -601,6 +601,101 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "triggersActionsUi", + "id": "def-public.fetchConnectorTypes", + "type": "Function", + "tags": [], + "label": "fetchConnectorTypes", + "description": [], + "signature": [ + "({ http, featureId, includeSystemActions, }: { http: ", + { + "pluginId": "@kbn/core-http-browser", + "scope": "common", + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-common.HttpSetup", + "text": "HttpSetup" + }, + "; featureId?: string | undefined; includeSystemActions?: boolean | undefined; }) => Promise<", + { + "pluginId": "@kbn/actions-types", + "scope": "common", + "docId": "kibKbnActionsTypesPluginApi", + "section": "def-common.ActionType", + "text": "ActionType" + }, + "[]>" + ], + "path": "packages/kbn-alerts-ui-shared/src/common/apis/fetch_connector_types/fetch_connector_types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "triggersActionsUi", + "id": "def-public.fetchConnectorTypes.$1", + "type": "Object", + "tags": [], + "label": "{\n http,\n featureId,\n includeSystemActions = false,\n}", + "description": [], + "path": "packages/kbn-alerts-ui-shared/src/common/apis/fetch_connector_types/fetch_connector_types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "triggersActionsUi", + "id": "def-public.fetchConnectorTypes.$1.http", + "type": "Object", + "tags": [], + "label": "http", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-browser", + "scope": "common", + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-common.HttpSetup", + "text": "HttpSetup" + } + ], + "path": "packages/kbn-alerts-ui-shared/src/common/apis/fetch_connector_types/fetch_connector_types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "triggersActionsUi", + "id": "def-public.fetchConnectorTypes.$1.featureId", + "type": "string", + "tags": [], + "label": "featureId", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-alerts-ui-shared/src/common/apis/fetch_connector_types/fetch_connector_types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "triggersActionsUi", + "id": "def-public.fetchConnectorTypes.$1.includeSystemActions", + "type": "CompoundType", + "tags": [], + "label": "includeSystemActions", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "packages/kbn-alerts-ui-shared/src/common/apis/fetch_connector_types/fetch_connector_types.ts", + "deprecated": false, + "trackAdoption": false + } + ] + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "triggersActionsUi", "id": "def-public.ForLastExpression", @@ -1084,101 +1179,6 @@ "returnComment": [], "initialIsOpen": false }, - { - "parentPluginId": "triggersActionsUi", - "id": "def-public.loadActionTypes", - "type": "Function", - "tags": [], - "label": "loadActionTypes", - "description": [], - "signature": [ - "({\n http,\n featureId,\n includeSystemActions = false,\n}: { http: ", - { - "pluginId": "@kbn/core-http-browser", - "scope": "common", - "docId": "kibKbnCoreHttpBrowserPluginApi", - "section": "def-common.HttpSetup", - "text": "HttpSetup" - }, - "; featureId?: string | undefined; includeSystemActions?: boolean | undefined; }) => Promise<", - { - "pluginId": "actions", - "scope": "common", - "docId": "kibActionsPluginApi", - "section": "def-common.ActionType", - "text": "ActionType" - }, - "[]>" - ], - "path": "x-pack/plugins/triggers_actions_ui/public/application/lib/action_connector_api/connector_types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "triggersActionsUi", - "id": "def-public.loadActionTypes.$1", - "type": "Object", - "tags": [], - "label": "{\n http,\n featureId,\n includeSystemActions = false,\n}", - "description": [], - "path": "x-pack/plugins/triggers_actions_ui/public/application/lib/action_connector_api/connector_types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "triggersActionsUi", - "id": "def-public.loadActionTypes.$1.http", - "type": "Object", - "tags": [], - "label": "http", - "description": [], - "signature": [ - { - "pluginId": "@kbn/core-http-browser", - "scope": "common", - "docId": "kibKbnCoreHttpBrowserPluginApi", - "section": "def-common.HttpSetup", - "text": "HttpSetup" - } - ], - "path": "x-pack/plugins/triggers_actions_ui/public/application/lib/action_connector_api/connector_types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "triggersActionsUi", - "id": "def-public.loadActionTypes.$1.featureId", - "type": "string", - "tags": [], - "label": "featureId", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/triggers_actions_ui/public/application/lib/action_connector_api/connector_types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "triggersActionsUi", - "id": "def-public.loadActionTypes.$1.includeSystemActions", - "type": "CompoundType", - "tags": [], - "label": "includeSystemActions", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/plugins/triggers_actions_ui/public/application/lib/action_connector_api/connector_types.ts", - "deprecated": false, - "trackAdoption": false - } - ] - } - ], - "returnComment": [], - "initialIsOpen": false - }, { "parentPluginId": "triggersActionsUi", "id": "def-public.loadRule", @@ -5986,7 +5986,7 @@ "tags": [], "label": "AlertProvidedActionVariables", "description": [], - "path": "x-pack/plugins/triggers_actions_ui/public/application/lib/action_variables.ts", + "path": "packages/kbn-alerts-ui-shared/src/action_variables/action_variables.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false diff --git a/api_docs/triggers_actions_ui.mdx b/api_docs/triggers_actions_ui.mdx index 9208a9d65f882..004f3e0c926b0 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-07-17 +date: 2024-07-19 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 5c81c67074e2d..1e3500c539df3 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-07-17 +date: 2024-07-19 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 2d58555a7d9ba..1d563442b4b80 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-07-17 +date: 2024-07-19 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 6815219f6d74b..cdbb03bb963f5 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-07-17 +date: 2024-07-19 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 8130e4b4f4139..fae85ad659383 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-07-17 +date: 2024-07-19 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 69ce40bc84e06..b2d4ea7620f47 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-07-17 +date: 2024-07-19 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 d3be4066c41af..31849f0937981 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-07-17 +date: 2024-07-19 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 565198cbd679f..7738e218b64f9 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-07-17 +date: 2024-07-19 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 e8d89853fa386..b379c1dc6350e 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-07-17 +date: 2024-07-19 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 6d2d0095fc84a..6ef4fd399a846 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-07-17 +date: 2024-07-19 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 958b5c8369bfb..2bde1f28fd1dd 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-07-17 +date: 2024-07-19 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 609e4f9cbff56..f70f8d1f114cb 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-07-17 +date: 2024-07-19 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 e933082a9301d..4cecd7a7a79a0 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-07-17 +date: 2024-07-19 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 7f8aab17837e5..b9c254a7d0b52 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-07-17 +date: 2024-07-19 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 09501f62b52ff..122c10af4e8a0 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-07-17 +date: 2024-07-19 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 3757c498e89b4..07ad0c0970fdc 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-07-17 +date: 2024-07-19 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 54a06308cb28e..d5203f87fb593 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-07-17 +date: 2024-07-19 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 2836b4b8e01f9..bf547931f1479 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-07-17 +date: 2024-07-19 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 473f0b3abb11f..eedaf072f26bf 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-07-17 +date: 2024-07-19 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 61e0e080a3bc7..cc2e9a57259b9 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-07-17 +date: 2024-07-19 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 2778cd1495449..ea03d31362c30 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeXy'] --- import visTypeXyObj from './vis_type_xy.devdocs.json'; diff --git a/api_docs/visualizations.mdx b/api_docs/visualizations.mdx index 33a0f343625d6..3f4b33fd72701 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-07-17 +date: 2024-07-19 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizations'] --- import visualizationsObj from './visualizations.devdocs.json'; diff --git a/docs/CHANGELOG.asciidoc b/docs/CHANGELOG.asciidoc index c5a1dd2798fbb..a7d48773e7b08 100644 --- a/docs/CHANGELOG.asciidoc +++ b/docs/CHANGELOG.asciidoc @@ -82,8 +82,6 @@ Dashboard:: * Fixes controls getting overwritten on navigation ({kibana-pull}187509[#187509]). Elastic Security:: For the Elastic Security 8.14.3 release information, refer to {security-guide}/release-notes.html[_Elastic Security Solution Release Notes_]. -Logs:: -* Fixes log entry fly-out when response is slow ({kibana-pull}187303[#187303]). [[release-notes-8.14.2]] == {kib} 8.14.2 diff --git a/docs/api/cases/cases-api-find-connectors.asciidoc b/docs/api/cases/cases-api-find-connectors.asciidoc index 974e3e9a2211b..7dac2f6f2e823 100644 --- a/docs/api/cases/cases-api-find-connectors.asciidoc +++ b/docs/api/cases/cases-api-find-connectors.asciidoc @@ -8,7 +8,7 @@ Retrieves information about <>. In particular, only the connectors that are supported for use in cases are returned. Refer to the list of supported external incident management systems in -<>. +<>. [NOTE] ==== diff --git a/docs/api/cases/cases-api-set-configuration.asciidoc b/docs/api/cases/cases-api-set-configuration.asciidoc index 6d7e9320672e6..6941dd05427d0 100644 --- a/docs/api/cases/cases-api-set-configuration.asciidoc +++ b/docs/api/cases/cases-api-set-configuration.asciidoc @@ -29,7 +29,7 @@ You must have `all` privileges for the *Cases* feature in the *Management*, === {api-description-title} Connectors are used to interface with external systems. You must create a -connector before you can use it in your cases. Refer to <>. +connector before you can use it in your cases. Refer to <>. If you set a default connector, it is automatically selected when you create cases in {kib}. If you use the <>, however, diff --git a/docs/api/cases/cases-api-update-configuration.asciidoc b/docs/api/cases/cases-api-update-configuration.asciidoc index b30a8f0bb79b2..57c803eb53bde 100644 --- a/docs/api/cases/cases-api-update-configuration.asciidoc +++ b/docs/api/cases/cases-api-update-configuration.asciidoc @@ -29,7 +29,7 @@ You must have `all` privileges for the *Cases* feature in the *Management*, === {api-description-title} Connectors are used to interface with external systems. You must create a -connector before you can it in your cases. Refer to <>. +connector before you can it in your cases. Refer to <>. === {api-path-parms-title} diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index 7c52908cc4e43..18102c1224431 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -588,7 +588,7 @@ activities. |{kib-repo}blob/{branch}/x-pack/plugins/fields_metadata/README.md[fieldsMetadata] -|The @kbn/fields-metadata-plugin is designed to provide a centralized and asynchronous way to consume field metadata across Kibana. This plugin addresses the need for on-demand retrieval of field metadata from static ECS definitions and integration manifests, with the flexibility to extend to additional resolution sources in the future. +|The @kbn/fields-metadata-plugin is designed to provide a centralized and asynchronous way to consume field metadata across Kibana. This plugin addresses the need for on-demand retrieval of field metadata from static ECS/Metadata definitions and integration manifests, with the flexibility to extend to additional resolution sources in the future. |{kib-repo}blob/{branch}/x-pack/plugins/file_upload[fileUpload] diff --git a/docs/management/cases/add-connectors.asciidoc b/docs/management/cases/add-connectors.asciidoc deleted file mode 100644 index 0ab72287a5384..0000000000000 --- a/docs/management/cases/add-connectors.asciidoc +++ /dev/null @@ -1,72 +0,0 @@ -[[add-case-connectors]] -== Add connectors to cases -:frontmatter-description: Configure connectors to push case details to external incident management systems. -:frontmatter-tags-products: [kibana] -:frontmatter-tags-content-type: [how-to] -:frontmatter-tags-user-goals: [configure] -++++ -Add connectors -++++ - -You can add connectors to cases to push information to these external incident -management systems: - -* {ibm-r} -* {jira} -* {sn-itsm} -* {sn-sir} -* {swimlane} -* {webhook-cm} - -NOTE: To create connectors and send cases to external systems, you must have the -appropriate {kib} feature privileges. Refer to <>. - -[discrete] -[[create-case-connectors]] -== Create connectors - -:frontmatter-description: Open and track issues in {kib} cases. -:frontmatter-tags-products: [kibana] -:frontmatter-tags-content-type: [overview] -:frontmatter-tags-user-goals: [analyze] - -You can create connectors in *{stack-manage-app} > {connectors-ui}*, -as described in <>. Alternatively, you can create them in -*{stack-manage-app} > Cases*: - -. Click *Settings*. -+ --- -[role="screenshot"] -image::images/cases-settings.png[View case settings] -// NOTE: This is an autogenerated screenshot. Do not edit it directly. --- - -. From the *Incident management system* list, select *Add new connector*. - -. Select an external incident management system. - -. Enter your required settings. Refer to <>, -<>, <>, <>, -<>, or <> for connector -configuration details. - -. Click *Save*. - -[discrete] -[[edit-case-connector-settings]] -== Edit connector settings - -You can create additional connectors, update existing connectors, change -the default connector, and change case closure options. - -. Go to *{stack-manage-app} > Cases* and click *Settings*. - -. To change whether cases are automatically closed after they are sent to an -external system, update the case closure options. - -. To change the default connector for new cases, select the connector from the -*Incident management system* list. - -. To update a connector, click *Update * and edit the connector -fields as required. diff --git a/docs/management/cases/cases.asciidoc b/docs/management/cases/cases.asciidoc index 1c0c53ee8aa9e..542b1fa59fb11 100644 --- a/docs/management/cases/cases.asciidoc +++ b/docs/management/cases/cases.asciidoc @@ -9,6 +9,8 @@ Cases are used to open and track issues directly in {kib}. You can add assignees and tags to your cases, set their severity and status, and add alerts, comments, and visualizations. You can create cases automatically when alerts occur or send cases to external incident management systems by configuring connectors. +You can also optionally add custom fields and case templates. preview:[] + [role="screenshot"] image::images/cases-list.png[Cases page] // NOTE: This is an autogenerated screenshot. Do not edit it directly. @@ -21,5 +23,4 @@ cases in *{stack-manage-app}*. * <> * <> -* <> -* <> \ No newline at end of file +* <> \ No newline at end of file diff --git a/docs/management/cases/images/cases-create.png b/docs/management/cases/images/cases-create.png index 1629348293d30..56f79b1f49d52 100644 Binary files a/docs/management/cases/images/cases-create.png and b/docs/management/cases/images/cases-create.png differ diff --git a/docs/management/cases/images/cases-custom-fields-view.png b/docs/management/cases/images/cases-custom-fields-view.png deleted file mode 100644 index c97f9f9dd75b5..0000000000000 Binary files a/docs/management/cases/images/cases-custom-fields-view.png and /dev/null differ diff --git a/docs/management/cases/images/cases-custom-fields.png b/docs/management/cases/images/cases-custom-fields.png deleted file mode 100644 index 07c3b4c2a0895..0000000000000 Binary files a/docs/management/cases/images/cases-custom-fields.png and /dev/null differ diff --git a/docs/management/cases/images/cases-settings.png b/docs/management/cases/images/cases-settings.png index be7cc6aee4994..b3b8f37d75ab6 100644 Binary files a/docs/management/cases/images/cases-settings.png and b/docs/management/cases/images/cases-settings.png differ diff --git a/docs/management/cases/images/cases-templates-add.png b/docs/management/cases/images/cases-templates-add.png new file mode 100644 index 0000000000000..20da0035ffb8c Binary files /dev/null and b/docs/management/cases/images/cases-templates-add.png differ diff --git a/docs/management/cases/images/cases-visualization.png b/docs/management/cases/images/cases-visualization.png index 59567f67683c6..ba36e88437a09 100644 Binary files a/docs/management/cases/images/cases-visualization.png and b/docs/management/cases/images/cases-visualization.png differ diff --git a/docs/management/cases/index.asciidoc b/docs/management/cases/index.asciidoc index b48aafc45f883..77b9058be1b79 100644 --- a/docs/management/cases/index.asciidoc +++ b/docs/management/cases/index.asciidoc @@ -1,4 +1,4 @@ include::cases.asciidoc[] include::setup-cases.asciidoc[leveloffset=+1] include::manage-cases.asciidoc[leveloffset=+1] -include::add-connectors.asciidoc[leveloffset=+1] +include::manage-cases-settings.asciidoc[leveloffset=+1] diff --git a/docs/management/cases/manage-cases-settings.asciidoc b/docs/management/cases/manage-cases-settings.asciidoc new file mode 100644 index 0000000000000..b0764c495101a --- /dev/null +++ b/docs/management/cases/manage-cases-settings.asciidoc @@ -0,0 +1,103 @@ +[[manage-cases-settings]] +== Configure case settings +:frontmatter-description: Change the default behavior of cases by adding connectors, custom fields, templates, and closure options. +:frontmatter-tags-products: [kibana] +:frontmatter-tags-content-type: [how-to] +:frontmatter-tags-user-goals: [configure] + +To change case closure options and add custom fields, templates, and connectors for external incident management systems, go to *{stack-manage-app} > Cases* and click *Settings*. + +To perform these tasks, you must have <> to the appropriate case and connector features in {kib}. + +[role="screenshot"] +image::images/cases-settings.png[View case settings] +// NOTE: This is an autogenerated screenshot. Do not edit it directly. + +[[case-closures]] +=== Case closures + +If you close cases in your external incident management system, they will remain open in *Cases* until you close them manually. + +To change whether cases are automatically closed after they are sent to an external system, update the case closure options. + +[[case-connectors]] +=== External incident management systems + +You can add connectors to cases to push information to these external incident +management systems: + +* {ibm-r} +* {jira} +* {sn-itsm} +* {sn-sir} +* {swimlane} +* {webhook-cm} + +NOTE: To create connectors and send cases to external systems, you must have the +appropriate {kib} feature privileges. Refer to <>. + +You can create connectors in *{stack-manage-app} > {connectors-ui}*, as described in <>. +Alternatively, you can create them in *{stack-manage-app} > Cases > Settings*: + +. From the *Incident management system* list, select *Add new connector*. + +. Select an external incident management system. + +. Enter your required settings. Refer to <>, +<>, <>, <>, +<>, or <> for connector +configuration details. + +You can subsequently choose the connector when you create cases and use it in case templates. +To change the default connector for new cases, select the connector from the +*Incident management system* list. + +To update a connector, click *Update * and edit the connector fields as required. + +[[case-custom-fields]] +=== Custom fields + +You can add optional and required fields for customized case collaboration. added:[8.15.0] + +To create a custom field: + +. In the *Custom fields* section, click *Add field*. ++ +-- +[role="screenshot"] +image::images/cases-custom-fields-add.png[Add a custom field in case settings] +// NOTE: This is an autogenerated screenshot. Do not edit it directly. +-- + +. You must provide a field label and type (text or toggle). + You can optionally designate it as a required field and provide a default value. + +When you create a custom field, it's added to all new and existing cases. +Existing cases have null values for new text fields until you set them in each case. + +You can subsequently remove or edit custom fields on the *Settings* page. + +[[case-templates]] +=== Templates + +preview::[] + +You can make the case creation process faster and more consistent by adding templates. +A template defines values for one or all of the case fields (such as severity, tags, description, and title) as well as any custom fields. + +To create a template: + +. In the *Templates* section, click *Add template*. ++ +-- +[role="screenshot"] +image::images/cases-templates-add.png[Add a template in case settings] +// NOTE: This is an autogenerated screenshot. Do not edit it directly. +-- + +. You must provide a template name and case severity. + You can optionally add template tags and a description, values for each case field, and a case connector. + +When users create cases, they can optionally select a template and use its values or override them. + +NOTE: If you update or delete templates, existing cases are unaffected. diff --git a/docs/management/cases/manage-cases.asciidoc b/docs/management/cases/manage-cases.asciidoc index ecf7c755a7a59..43ce39e39baa3 100644 --- a/docs/management/cases/manage-cases.asciidoc +++ b/docs/management/cases/manage-cases.asciidoc @@ -6,6 +6,8 @@ :frontmatter-tags-content-type: [how-to] :frontmatter-tags-user-goals: [analyze] +To perform these tasks, you must have <> to the appropriate case features in {kib}. + [[open-case]] === Open a new case @@ -19,6 +21,8 @@ image::images/cases-create.png[Create a case in {stack-manage-app}] // NOTE: This is an autogenerated screenshot. Do not edit it directly. -- +. If you defined <>, you can optionally select one to use its default field values. preview:[] + . Give the case a name, severity, and description. + TIP: In the `Description` area, you can use @@ -28,11 +32,10 @@ text. . Optionally, add a category, assignees, and tags. You can add users only if they meet the necessary <>. -. preview:[] If you defined any custom fields, they appear in the *Additional fields* section. -Check out <>. +. If you defined any <>, they appear in the *Additional fields* section. added:[8.15.0] . For the *External incident management system*, select a connector. For more -information, refer to <>. +information, refer to <>. . After you've completed all of the required fields, click *Create case*. @@ -41,52 +44,6 @@ By default, the rule adds all of the alerts within a specified time window to a You can optionally choose a field to group the alerts and create separate cases for each group. You can also choose whether you want the rule to reopen cases or open new ones when the time window elapses. -[[case-custom-fields]] -=== Add custom fields - -preview::[] - -You can add optional and required fields for customized case collaboration. - -. Go to *{stack-manage-app} > Cases* and click *Settings*. -+ --- -[role="screenshot"] -image::images/cases-custom-fields-view.png[View custom fields in case settings] -// NOTE: This is an autogenerated screenshot. Do not edit it directly. - -NOTE: To view and change case settings, you must have the appropriate {kib} feature privileges. Refer to <>. --- - -. In the *Custom fields* section, click *Add field*. -+ --- -[role="screenshot"] -image::images/cases-custom-fields-add.png[Add a custom field in case settings] -// NOTE: This is an autogenerated screenshot. Do not edit it directly. --- - -. Enter a field label. - -. Choose a field type: text or toggle. - -. If you want the text field to be mandatory in all cases, select *Make this field required*. - -. Optionally add a default value. - -. Click *Save field*. - -You can subsequently remove or edit custom fields on the *Settings* page. - -After you create custom fields, they're added to all new and existing cases. - -Existing cases have null values for the new text fields until you set them in each case. -For example, you must click the pencil icon next to `my-field` to set it: - -[role="screenshot"] -image::images/cases-custom-fields.png[A case that has an unset custom field] -// NOTE: This is an autogenerated screenshot. Do not edit it directly. - [[add-case-notifications]] === Add email notifications diff --git a/docs/redirects.asciidoc b/docs/redirects.asciidoc index be017fbd1c94e..767037d39536d 100644 --- a/docs/redirects.asciidoc +++ b/docs/redirects.asciidoc @@ -432,4 +432,9 @@ This connector was renamed. Refer to <>. == APIs For the most up-to-date API details, refer to the -{kib-repo}/tree/{branch}/x-pack/plugins/alerting/docs/openapi[alerting], {kib-repo}/tree/{branch}/x-pack/plugins/cases/docs/openapi[cases], {kib-repo}/tree/{branch}/x-pack/plugins/actions/docs/openapi[connectors], and {kib-repo}/tree/{branch}/x-pack/plugins/ml/common/openapi[machine learning] open API specifications. \ No newline at end of file +{kib-repo}/tree/{branch}/x-pack/plugins/alerting/docs/openapi[alerting], {kib-repo}/tree/{branch}/x-pack/plugins/cases/docs/openapi[cases], {kib-repo}/tree/{branch}/x-pack/plugins/actions/docs/openapi[connectors], and {kib-repo}/tree/{branch}/x-pack/plugins/ml/common/openapi[machine learning] open API specifications. + +[role="exclude",id="add-case-connectors"] +== Add connectors to cases + +This content has moved. Refer to <>. \ No newline at end of file diff --git a/examples/controls_example/public/app/react_control_example.tsx b/examples/controls_example/public/app/react_control_example.tsx index 82ae768898ba1..5dbf72cd02813 100644 --- a/examples/controls_example/public/app/react_control_example.tsx +++ b/examples/controls_example/public/app/react_control_example.tsx @@ -20,7 +20,11 @@ import { EuiSuperDatePicker, OnTimeChangeProps, } from '@elastic/eui'; -import { CONTROL_GROUP_TYPE } from '@kbn/controls-plugin/common'; +import { + CONTROL_GROUP_TYPE, + DEFAULT_CONTROL_GROW, + DEFAULT_CONTROL_WIDTH, +} from '@kbn/controls-plugin/common'; import { CoreStart } from '@kbn/core/public'; import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import { ReactEmbeddableRenderer, ViewMode } from '@kbn/embeddable-plugin/public'; @@ -39,6 +43,7 @@ import { ControlGroupApi } from '../react_controls/control_group/types'; import { RANGE_SLIDER_CONTROL_TYPE } from '../react_controls/data_controls/range_slider/types'; import { SEARCH_CONTROL_TYPE } from '../react_controls/data_controls/search_control/types'; import { TIMESLIDER_CONTROL_TYPE } from '../react_controls/timeslider_control/types'; +import { openDataControlEditor } from '../react_controls/data_controls/open_data_control_editor'; const toggleViewButtons = [ { @@ -167,6 +172,7 @@ export const ReactControlExample = ({ addNewPanel: () => { return Promise.resolve(undefined); }, + lastUsedDataViewId: new BehaviorSubject(WEB_LOGS_DATA_VIEW_ID), }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -282,6 +288,35 @@ export const ReactControlExample = ({ Serialize control group + {controlGroupApi && ( + + { + openDataControlEditor({ + initialState: { + grow: DEFAULT_CONTROL_GROW, + width: DEFAULT_CONTROL_WIDTH, + dataViewId: dashboardApi.lastUsedDataViewId.getValue(), + }, + onSave: ({ type: controlType, state: initialState }) => { + controlGroupApi.addNewPanel({ + panelType: controlType, + initialState, + }); + }, + controlGroupApi, + services: { + core, + dataViews: dataViewsService, + }, + }); + }} + size="s" + > + Add new data control + + + )} deserializeControlGroup(state), buildEmbeddable: async (initialState, buildApi, uuid, parentApi, setApi) => { const { - initialChildControlState: childControlState, + initialChildControlState, defaultControlGrow, defaultControlWidth, labelPosition, @@ -71,12 +70,9 @@ export const getControlGroupEmbeddableFactory = (services: { ignoreParentSettings, } = initialState; + const controlsManager = initControlsManager(initialChildControlState); const autoApplySelections$ = new BehaviorSubject(autoApplySelections); const timeslice$ = new BehaviorSubject<[number, number] | undefined>(undefined); - const children$ = new BehaviorSubject<{ [key: string]: DefaultControlApi }>({}); - function getControlApi(controlUuid: string) { - return children$.value[controlUuid]; - } const filters$ = new BehaviorSubject([]); const dataViews = new BehaviorSubject(undefined); const chainingSystem$ = new BehaviorSubject(chainingSystem); @@ -108,19 +104,16 @@ export const getControlGroupEmbeddableFactory = (services: { undefined ); - const controlsInOrder$ = new BehaviorSubject>( - Object.keys(childControlState) - .map((key) => ({ - id: key, - order: childControlState[key].order, - type: childControlState[key].type, - })) - .sort((a, b) => (a.order > b.order ? 1 : -1)) - ); const api = setApi({ + ...controlsManager.api, controlFetch$: (controlUuid: string) => controlFetch$( - chaining$(controlUuid, chainingSystem$, controlsInOrder$, getControlApi), + chaining$( + controlUuid, + chainingSystem$, + controlsManager.controlsInOrder$, + controlsManager.getControlApi + ), controlGroupFetch$(ignoreParentSettings$, parentApi ? parentApi : {}) ), ignoreParentSettings$, @@ -134,9 +127,6 @@ export const getControlGroupEmbeddableFactory = (services: { return {} as unknown as ControlGroupRuntimeState; }, dataLoading: dataLoading$, - children$: children$ as PublishingSubject<{ - [key: string]: unknown; - }>, onEdit: async () => { openEditControlGroupFlyout( api, @@ -154,34 +144,18 @@ export const getControlGroupEmbeddableFactory = (services: { i18n.translate('controls.controlGroup.displayName', { defaultMessage: 'Controls', }), - getSerializedStateForChild: (childId) => { - return { rawState: childControlState[childId] }; - }, serializeState: () => { - return serializeControlGroup( - children$.getValue(), - controlsInOrder$.getValue().map(({ id }) => id), - { - labelPosition: labelPosition$.getValue(), + const { panelsJSON, references } = controlsManager.serializeControls(); + return { + rawState: { chainingSystem: chainingSystem$.getValue(), - autoApplySelections: autoApplySelections$.getValue(), - ignoreParentSettings: ignoreParentSettings$.getValue(), - } - ); - }, - getPanelCount: () => { - return (Object.keys(children$.getValue()) ?? []).length; - }, - addNewPanel: (panel) => { - // TODO: Add a new child control - return Promise.resolve(undefined); - }, - removePanel: (panelId) => { - // TODO: Remove a child control - }, - replacePanel: async (panelId, newPanel) => { - // TODO: Replace a child control - return Promise.resolve(panelId); + controlStyle: labelPosition$.getValue(), // Rename "labelPosition" to "controlStyle" + showApplySelections: !autoApplySelections$.getValue(), + ignoreParentSettingsJSON: JSON.stringify(ignoreParentSettings$.getValue()), + panelsJSON, + }, + references, + }; }, grow, width, @@ -238,7 +212,7 @@ export const getControlGroupEmbeddableFactory = (services: { return { api, Component: () => { - const controlsInOrder = useStateFromPublishingSubject(controlsInOrder$); + const controlsInOrder = useStateFromPublishingSubject(controlsManager.controlsInOrder$); useEffect(() => { return () => { @@ -253,14 +227,11 @@ export const getControlGroupEmbeddableFactory = (services: { {controlsInOrder.map(({ id, type }) => ( api} onApiAvailable={(controlApi) => { - children$.next({ - ...children$.getValue(), - [id]: controlApi, - }); + controlsManager.setControlApi(id, controlApi); }} /> ))} diff --git a/examples/controls_example/public/react_controls/control_group/init_controls_manager.test.ts b/examples/controls_example/public/react_controls/control_group/init_controls_manager.test.ts new file mode 100644 index 0000000000000..450d882108892 --- /dev/null +++ b/examples/controls_example/public/react_controls/control_group/init_controls_manager.test.ts @@ -0,0 +1,68 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { DefaultControlApi } from '../types'; +import { initControlsManager } from './init_controls_manager'; + +jest.mock('uuid', () => ({ + v4: jest.fn().mockReturnValue('delta'), +})); + +describe('PresentationContainer api', () => { + test('addNewPanel should add control at end of controls', async () => { + const controlsManager = initControlsManager({ + alpha: { type: 'whatever', order: 0 }, + bravo: { type: 'whatever', order: 1 }, + charlie: { type: 'whatever', order: 2 }, + }); + const addNewPanelPromise = controlsManager.api.addNewPanel({ + panelType: 'whatever', + initialState: {}, + }); + controlsManager.setControlApi('delta', {} as unknown as DefaultControlApi); + await addNewPanelPromise; + expect(controlsManager.controlsInOrder$.value.map((element) => element.id)).toEqual([ + 'alpha', + 'bravo', + 'charlie', + 'delta', + ]); + }); + + test('removePanel should remove control', () => { + const controlsManager = initControlsManager({ + alpha: { type: 'whatever', order: 0 }, + bravo: { type: 'whatever', order: 1 }, + charlie: { type: 'whatever', order: 2 }, + }); + controlsManager.api.removePanel('bravo'); + expect(controlsManager.controlsInOrder$.value.map((element) => element.id)).toEqual([ + 'alpha', + 'charlie', + ]); + }); + + test('replacePanel should replace control', async () => { + const controlsManager = initControlsManager({ + alpha: { type: 'whatever', order: 0 }, + bravo: { type: 'whatever', order: 1 }, + charlie: { type: 'whatever', order: 2 }, + }); + const replacePanelPromise = controlsManager.api.replacePanel('bravo', { + panelType: 'whatever', + initialState: {}, + }); + controlsManager.setControlApi('delta', {} as unknown as DefaultControlApi); + await replacePanelPromise; + expect(controlsManager.controlsInOrder$.value.map((element) => element.id)).toEqual([ + 'alpha', + 'delta', + 'charlie', + ]); + }); +}); diff --git a/examples/controls_example/public/react_controls/control_group/init_controls_manager.ts b/examples/controls_example/public/react_controls/control_group/init_controls_manager.ts new file mode 100644 index 0000000000000..2ba2d4767c07b --- /dev/null +++ b/examples/controls_example/public/react_controls/control_group/init_controls_manager.ts @@ -0,0 +1,158 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { v4 as generateId } from 'uuid'; +import { + HasSerializedChildState, + PanelPackage, + PresentationContainer, +} from '@kbn/presentation-containers'; +import { Reference } from '@kbn/content-management-utils'; +import { BehaviorSubject, merge } from 'rxjs'; +import { PublishingSubject } from '@kbn/presentation-publishing'; +import { omit } from 'lodash'; +import { ControlPanelsState, ControlPanelState } from './types'; +import { DefaultControlApi, DefaultControlState } from '../types'; + +export function initControlsManager(initialControlPanelsState: ControlPanelsState) { + const children$ = new BehaviorSubject<{ [key: string]: DefaultControlApi }>({}); + const controlsPanelState: { [panelId: string]: DefaultControlState } = { + ...initialControlPanelsState, + }; + const controlsInOrder$ = new BehaviorSubject>( + Object.keys(initialControlPanelsState) + .map((key) => ({ + id: key, + order: initialControlPanelsState[key].order, + type: initialControlPanelsState[key].type, + })) + .sort((a, b) => (a.order > b.order ? 1 : -1)) + ); + + function untilControlLoaded( + id: string + ): DefaultControlApi | Promise { + if (children$.value[id]) { + return children$.value[id]; + } + + return new Promise((resolve) => { + const subscription = merge(children$, controlsInOrder$).subscribe(() => { + if (children$.value[id]) { + subscription.unsubscribe(); + resolve(children$.value[id]); + return; + } + + // control removed before the control finished loading. + const controlState = controlsInOrder$.value.find((element) => element.id === id); + if (!controlState) { + subscription.unsubscribe(); + resolve(undefined); + } + }); + }); + } + + function getControlApi(controlUuid: string) { + return children$.value[controlUuid]; + } + + async function addNewPanel( + { panelType, initialState }: PanelPackage, + index: number + ) { + const id = generateId(); + const nextControlsInOrder = [...controlsInOrder$.value]; + nextControlsInOrder.splice(index, 0, { + id, + type: panelType, + }); + controlsInOrder$.next(nextControlsInOrder); + controlsPanelState[id] = initialState ?? {}; + return await untilControlLoaded(id); + } + + function removePanel(panelId: string) { + delete controlsPanelState[panelId]; + controlsInOrder$.next(controlsInOrder$.value.filter(({ id }) => id !== panelId)); + children$.next(omit(children$.value, panelId)); + } + + return { + controlsInOrder$: controlsInOrder$ as PublishingSubject>, + getControlApi, + setControlApi: (uuid: string, controlApi: DefaultControlApi) => { + children$.next({ + ...children$.getValue(), + [uuid]: controlApi, + }); + }, + serializeControls: () => { + const references: Reference[] = []; + const explicitInputPanels: { + [panelId: string]: ControlPanelState & { explicitInput: object }; + } = {}; + + controlsInOrder$.getValue().forEach(({ id }, index) => { + const controlApi = getControlApi(id); + if (!controlApi) { + return; + } + + const { + rawState: { grow, width, ...rest }, + references: controlReferences, + } = controlApi.serializeState(); + + if (controlReferences && controlReferences.length > 0) { + references.push(...controlReferences); + } + + explicitInputPanels[id] = { + grow, + order: index, + type: controlApi.type, + width, + /** Re-add the `explicitInput` layer on serialize so control group saved object retains shape */ + explicitInput: rest, + }; + }); + + return { + panelsJSON: JSON.stringify(explicitInputPanels), + references, + }; + }, + api: { + getSerializedStateForChild: (childId: string) => { + const controlPanelState = controlsPanelState[childId]; + return controlPanelState ? { rawState: controlPanelState } : undefined; + }, + children$: children$ as PublishingSubject<{ + [key: string]: DefaultControlApi; + }>, + getPanelCount: () => { + return controlsInOrder$.value.length; + }, + addNewPanel: async (panel: PanelPackage) => { + return addNewPanel(panel, controlsInOrder$.value.length); + }, + removePanel, + replacePanel: async (panelId, newPanel) => { + const index = controlsInOrder$.value.findIndex(({ id }) => id === panelId); + removePanel(panelId); + const controlApi = await addNewPanel( + newPanel, + index >= 0 ? index : controlsInOrder$.value.length + ); + return controlApi ? controlApi.uuid : ''; + }, + } as PresentationContainer & HasSerializedChildState, + }; +} diff --git a/examples/controls_example/public/react_controls/control_group/serialization_utils.ts b/examples/controls_example/public/react_controls/control_group/serialization_utils.ts index 4d0f2eb0f749a..b38b22fc04249 100644 --- a/examples/controls_example/public/react_controls/control_group/serialization_utils.ts +++ b/examples/controls_example/public/react_controls/control_group/serialization_utils.ts @@ -6,11 +6,9 @@ * Side Public License, v 1. */ -import { Reference } from '@kbn/content-management-utils'; import { DEFAULT_CONTROL_GROW, DEFAULT_CONTROL_WIDTH } from '@kbn/controls-plugin/common'; import { SerializedPanelState } from '@kbn/presentation-containers'; import { omit } from 'lodash'; -import { DefaultControlApi } from '../types'; import { ControlGroupRuntimeState, ControlGroupSerializedState } from './types'; export const deserializeControlGroup = ( @@ -46,59 +44,9 @@ export const deserializeControlGroup = ( autoApplySelections: typeof state.rawState.showApplySelections === 'boolean' ? !state.rawState.showApplySelections - : false, + : false, // Rename "showApplySelections" to "autoApplySelections" labelPosition: state.rawState.controlStyle, // Rename "controlStyle" to "labelPosition" defaultControlGrow: DEFAULT_CONTROL_GROW, defaultControlWidth: DEFAULT_CONTROL_WIDTH, }; }; - -export const serializeControlGroup = ( - children: { - [key: string]: DefaultControlApi; - }, - idsInOrder: string[], - state: Omit< - ControlGroupRuntimeState, - | 'anyChildHasUnsavedChanges' - | 'defaultControlGrow' - | 'defaultControlWidth' - | 'initialChildControlState' - > -): SerializedPanelState => { - let references: Reference[] = []; - - /** Re-add the `explicitInput` layer on serialize so control group saved object retains shape */ - const explicitInputPanels = Object.keys(children).reduce((prev, panelId) => { - const child: DefaultControlApi = children[panelId]; - const type = child.type; - const { - rawState: { grow, width, ...rest }, - references: childReferences, - } = child.serializeState(); - - if (childReferences && childReferences.length > 0) { - references = [...references, ...childReferences]; - } - - /** - * Note: With legacy control embeddables, `grow` and `width` were duplicated under - * explicit input - this is no longer the case. - */ - return { - ...prev, - [panelId]: { grow, order: idsInOrder.indexOf(panelId), type, width, explicitInput: rest }, - }; - }, {}); - - return { - rawState: { - ...omit(state, ['ignoreParentSettings', 'labelPosition']), - controlStyle: state.labelPosition, // Rename "labelPosition" to "controlStyle" - showApplySelections: !state.autoApplySelections, - ignoreParentSettingsJSON: JSON.stringify(state.ignoreParentSettings), - panelsJSON: JSON.stringify(explicitInputPanels), - }, - references, - }; -}; diff --git a/examples/controls_example/public/react_controls/control_panel.scss b/examples/controls_example/public/react_controls/control_panel.scss index bd347ac124d4d..5a08475da3414 100644 --- a/examples/controls_example/public/react_controls/control_panel.scss +++ b/examples/controls_example/public/react_controls/control_panel.scss @@ -1,7 +1,7 @@ .controlPanel { width: 100%; max-inline-size: 100% !important; - height: calc($euiButtonHeight - 2px); + height: $euiButtonHeight; box-shadow: none !important; background-color: $euiFormBackgroundColor !important; @@ -10,14 +10,16 @@ border-radius: $euiBorderRadius !important; } - &--label { - @include euiTextTruncate; + &--labelWrapper { max-width: 40%; - background-color: transparent; - border-radius: $euiBorderRadius; - margin-left: 0 !important; - padding-left: 0 !important; + .controlPanel--label { + @include euiTextTruncate; + background-color: transparent; + border-radius: $euiBorderRadius; + margin-left: 0 !important; + padding-left: 0 !important; + } } &--hideComponent { diff --git a/examples/controls_example/public/react_controls/control_panel.tsx b/examples/controls_example/public/react_controls/control_panel.tsx index a427b3ed1801a..95ff67e60b34c 100644 --- a/examples/controls_example/public/react_controls/control_panel.tsx +++ b/examples/controls_example/public/react_controls/control_panel.tsx @@ -9,7 +9,14 @@ import classNames from 'classnames'; import React, { useState } from 'react'; -import { EuiFlexItem, EuiFormControlLayout, EuiFormLabel, EuiFormRow, EuiIcon } from '@elastic/eui'; +import { + EuiFlexItem, + EuiFormControlLayout, + EuiFormLabel, + EuiFormRow, + EuiIcon, + EuiToolTip, +} from '@elastic/eui'; import { ViewMode } from '@kbn/embeddable-plugin/public'; import { i18n } from '@kbn/i18n'; import { @@ -135,12 +142,18 @@ export const ControlPanel = + {api?.CustomPrependComponent ? ( ) : usingTwoLineLayout ? null : ( - - {panelTitle || defaultPanelTitle} - + + + {panelTitle || defaultPanelTitle} + + )} } diff --git a/examples/controls_example/public/react_controls/control_renderer.tsx b/examples/controls_example/public/react_controls/control_renderer.tsx index feea0269ee883..ce8d91ce0fa02 100644 --- a/examples/controls_example/public/react_controls/control_renderer.tsx +++ b/examples/controls_example/public/react_controls/control_renderer.tsx @@ -8,7 +8,6 @@ import React, { useImperativeHandle, useMemo } from 'react'; import { BehaviorSubject } from 'rxjs'; -import { v4 as generateId } from 'uuid'; import { StateComparators } from '@kbn/presentation-publishing'; @@ -25,12 +24,12 @@ export const ControlRenderer = < ApiType extends DefaultControlApi = DefaultControlApi >({ type, - maybeId, + uuid, getParentApi, onApiAvailable, }: { type: string; - maybeId?: string; + uuid: string; getParentApi: () => ControlGroupApi; onApiAvailable?: (api: ApiType) => void; }) => { @@ -38,7 +37,6 @@ export const ControlRenderer = < () => (() => { const parentApi = getParentApi(); - const uuid = maybeId ?? generateId(); const factory = getControlFactory(type); const buildApi = ( diff --git a/examples/controls_example/public/react_controls/data_controls/data_control_editor.test.tsx b/examples/controls_example/public/react_controls/data_controls/data_control_editor.test.tsx new file mode 100644 index 0000000000000..d90e5349f36d8 --- /dev/null +++ b/examples/controls_example/public/react_controls/data_controls/data_control_editor.test.tsx @@ -0,0 +1,241 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; +import { BehaviorSubject } from 'rxjs'; + +import { createStubDataView } from '@kbn/data-views-plugin/common/data_view.stub'; +import { stubFieldSpecMap } from '@kbn/data-views-plugin/common/field.stub'; +import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; +import { TimeRange } from '@kbn/es-query'; +import { I18nProvider } from '@kbn/i18n-react'; +import { act, fireEvent, render, RenderResult, waitFor } from '@testing-library/react'; + +import { getAllControlTypes, getControlFactory } from '../control_factory_registry'; +jest.mock('../control_factory_registry', () => ({ + ...jest.requireActual('../control_factory_registry'), + getAllControlTypes: jest.fn(), + getControlFactory: jest.fn(), +})); +import { DEFAULT_CONTROL_GROW, DEFAULT_CONTROL_WIDTH } from '@kbn/controls-plugin/common'; +import { ControlGroupApi } from '../control_group/types'; +import { DataControlEditor } from './data_control_editor'; +import { DataControlEditorState } from './open_data_control_editor'; +import { + getMockedOptionsListControlFactory, + getMockedRangeSliderControlFactory, + getMockedSearchControlFactory, +} from './mocks/data_control_mocks'; +import { ControlFactory } from '../types'; +import { DataControlApi, DefaultDataControlState } from './types'; + +const mockDataViews = dataViewPluginMocks.createStartContract(); +const mockDataView = createStubDataView({ + spec: { + id: 'logstash-*', + fields: { + ...stubFieldSpecMap, + 'machine.os.raw': { + name: 'machine.os.raw', + customLabel: 'OS', + type: 'string', + esTypes: ['keyword'], + aggregatable: true, + searchable: true, + }, + }, + title: 'logstash-*', + timeFieldName: '@timestamp', + }, +}); +mockDataViews.get = jest.fn().mockResolvedValue(mockDataView); + +const dashboardApi = { + timeRange$: new BehaviorSubject(undefined), + lastUsedDataViewId$: new BehaviorSubject(mockDataView.id!), +}; +const controlGroupApi = { + parentApi: dashboardApi, + grow: new BehaviorSubject(DEFAULT_CONTROL_GROW), + width: new BehaviorSubject(DEFAULT_CONTROL_WIDTH), +} as unknown as ControlGroupApi; + +describe('Data control editor', () => { + const mountComponent = async ({ + initialState, + }: { + initialState?: Partial; + }) => { + mockDataViews.get = jest.fn().mockResolvedValue(mockDataView); + + const controlEditor = render( + + {}} + onSave={() => {}} + parentApi={controlGroupApi} + initialState={{ + dataViewId: dashboardApi.lastUsedDataViewId$.getValue(), + ...initialState, + }} + services={{ dataViews: mockDataViews }} + /> + + ); + + await waitFor(() => { + expect(mockDataViews.get).toHaveBeenCalledTimes(1); + }); + + return controlEditor; + }; + + const selectField = async (controlEditor: RenderResult, fieldName: string) => { + expect(controlEditor.queryByTestId(`field-picker-select-${fieldName}`)).toBeInTheDocument(); + await act(async () => { + fireEvent.click(controlEditor.getByTestId(`field-picker-select-${fieldName}`)); + }); + }; + + const getPressedAttribute = (controlEditor: RenderResult, testId: string) => { + return controlEditor.getByTestId(testId).getAttribute('aria-pressed'); + }; + + beforeAll(() => { + const mockRegistry: { [key: string]: ControlFactory } = + { + search: getMockedSearchControlFactory({ parentApi: controlGroupApi }), + optionsList: getMockedOptionsListControlFactory({ parentApi: controlGroupApi }), + rangeSlider: getMockedRangeSliderControlFactory({ parentApi: controlGroupApi }), + }; + (getAllControlTypes as jest.Mock).mockReturnValue(Object.keys(mockRegistry)); + (getControlFactory as jest.Mock).mockImplementation((key) => mockRegistry[key]); + }); + + describe('creating a new control', () => { + test('field list does not include fields that are not compatible with any control types', async () => { + const controlEditor = await mountComponent({}); + const nonAggOption = controlEditor.queryByTestId('field-picker-select-machine.os'); + expect(nonAggOption).not.toBeInTheDocument(); + }); + + test('cannot save before selecting a field', async () => { + const controlEditor = await mountComponent({}); + + const saveButton = controlEditor.getByTestId('control-editor-save'); + expect(saveButton).toBeDisabled(); + await selectField(controlEditor, 'machine.os.raw'); + expect(saveButton).toBeEnabled(); + }); + + test('selecting a keyword field - can only create an options list control', async () => { + const controlEditor = await mountComponent({}); + await selectField(controlEditor, 'machine.os.raw'); + + expect(controlEditor.getByTestId('create__optionsList')).toBeEnabled(); + expect(controlEditor.getByTestId('create__rangeSlider')).not.toBeEnabled(); + expect(controlEditor.getByTestId('create__search')).not.toBeEnabled(); + }); + + test('selecting an IP field - can only create an options list control', async () => { + const controlEditor = await mountComponent({}); + await selectField(controlEditor, 'clientip'); + + expect(controlEditor.getByTestId('create__optionsList')).toBeEnabled(); + expect(controlEditor.getByTestId('create__rangeSlider')).not.toBeEnabled(); + expect(controlEditor.getByTestId('create__search')).not.toBeEnabled(); + }); + + describe('selecting a number field', () => { + let controlEditor: RenderResult; + + beforeEach(async () => { + controlEditor = await mountComponent({}); + await selectField(controlEditor, 'bytes'); + }); + + test('can create an options list or range slider control', () => { + expect(controlEditor.getByTestId('create__optionsList')).toBeEnabled(); + expect(controlEditor.getByTestId('create__rangeSlider')).toBeEnabled(); + expect(controlEditor.getByTestId('create__search')).not.toBeEnabled(); + }); + + test('defaults to options list creation', () => { + expect(getPressedAttribute(controlEditor, 'create__optionsList')).toBe('true'); + expect(getPressedAttribute(controlEditor, 'create__rangeSlider')).toBe('false'); + }); + }); + + test('renders custom settings when provided', async () => { + const controlEditor = await mountComponent({}); + await selectField(controlEditor, 'machine.os.raw'); + expect(controlEditor.queryByTestId('optionsListCustomSettings')).toBeInTheDocument(); + }); + }); + + test('selects the default width and grow', async () => { + const controlEditor = await mountComponent({}); + + expect(getPressedAttribute(controlEditor, 'control-editor-width-small')).toBe('false'); + expect(getPressedAttribute(controlEditor, 'control-editor-width-medium')).toBe('true'); + expect(getPressedAttribute(controlEditor, 'control-editor-width-large')).toBe('false'); + expect( + controlEditor.getByTestId('control-editor-grow-switch').getAttribute('aria-checked') + ).toBe(`${DEFAULT_CONTROL_GROW}`); + }); + + describe('editing existing control', () => { + describe('control title', () => { + test('auto-fills input with the default title', async () => { + const controlEditor = await mountComponent({ + initialState: { + controlType: 'optionsList', + controlId: 'testId', + fieldName: 'machine.os.raw', + defaultPanelTitle: 'OS', + }, + }); + const titleInput = await controlEditor.findByTestId('control-editor-title-input'); + expect(titleInput.getAttribute('value')).toBe('OS'); + expect(titleInput.getAttribute('placeholder')).toBe('OS'); + }); + + test('auto-fills input with the custom title', async () => { + const controlEditor = await mountComponent({ + initialState: { + controlType: 'optionsList', + controlId: 'testId', + fieldName: 'machine.os.raw', + title: 'Custom title', + }, + }); + const titleInput = await controlEditor.findByTestId('control-editor-title-input'); + expect(titleInput.getAttribute('value')).toBe('Custom title'); + expect(titleInput.getAttribute('placeholder')).toBe('machine.os.raw'); + }); + }); + + test('selects the provided control type', async () => { + const controlEditor = await mountComponent({ + initialState: { + controlType: 'rangeSlider', + controlId: 'testId', + fieldName: 'bytes', + }, + }); + + expect(controlEditor.getByTestId('create__optionsList')).toBeEnabled(); + expect(controlEditor.getByTestId('create__rangeSlider')).toBeEnabled(); + expect(controlEditor.getByTestId('create__search')).not.toBeEnabled(); + + expect(getPressedAttribute(controlEditor, 'create__optionsList')).toBe('false'); + expect(getPressedAttribute(controlEditor, 'create__rangeSlider')).toBe('true'); + expect(getPressedAttribute(controlEditor, 'create__search')).toBe('false'); + }); + }); +}); diff --git a/examples/controls_example/public/react_controls/data_controls/data_control_editor.tsx b/examples/controls_example/public/react_controls/data_controls/data_control_editor.tsx index c35462b66ecb2..5e0079342a6df 100644 --- a/examples/controls_example/public/react_controls/data_controls/data_control_editor.tsx +++ b/examples/controls_example/public/react_controls/data_controls/data_control_editor.tsx @@ -48,20 +48,16 @@ import { import { getAllControlTypes, getControlFactory } from '../control_factory_registry'; import { ControlGroupApi } from '../control_group/types'; -import { ControlStateManager } from '../types'; import { DataControlEditorStrings } from './data_control_constants'; import { getDataControlFieldRegistry } from './data_control_editor_utils'; -import { DataControlFactory, DefaultDataControlState, isDataControlFactory } from './types'; +import { DataControlEditorState } from './open_data_control_editor'; +import { DataControlFactory, isDataControlFactory } from './types'; -export interface ControlEditorProps< - State extends DefaultDataControlState = DefaultDataControlState -> { - controlId?: string; // if provided, then editing existing control; otherwise, creating a new control - controlType?: string; - onCancel: () => void; - onSave: (type?: string) => void; - stateManager: ControlStateManager; +export interface ControlEditorProps { + initialState: State; parentApi: ControlGroupApi; // controls must always have a parent API + onCancel: (newState: State) => void; + onSave: (newState: State, type: string) => void; services: { dataViews: DataViewsPublicPluginStart; }; @@ -77,7 +73,7 @@ const CompatibleControlTypesComponent = ({ setSelectedControlType, }: { fieldRegistry?: DataControlFieldRegistry; - selectedFieldName: string; + selectedFieldName?: string; selectedControlType?: string; setSelectedControlType: (type: string) => void; }) => { @@ -129,38 +125,28 @@ const CompatibleControlTypesComponent = ({ ); }; -export const DataControlEditor = ({ - controlId, - controlType, +export const DataControlEditor = ({ + initialState, onSave, onCancel, - stateManager, parentApi: controlGroup, /** TODO: These should not be props */ services: { dataViews: dataViewService }, -}: ControlEditorProps) => { - const [ - selectedDataViewId, - selectedFieldName, - currentTitle, - selectedGrow, - selectedWidth, - defaultGrow, - defaultWidth, - ] = useBatchedPublishingSubjects( - stateManager.dataViewId, - stateManager.fieldName, - stateManager.title, - stateManager.grow, - stateManager.width, +}: ControlEditorProps) => { + const [defaultGrow, defaultWidth] = useBatchedPublishingSubjects( controlGroup.grow, controlGroup.width - // controlGroup.lastUsedDataViewId, // TODO: Implement last used data view id + // controlGroup.parentApi?.lastUsedDataViewId, // TODO: Make this work ); - - const [selectedFieldDisplayName, setSelectedFieldDisplayName] = useState(selectedFieldName); - const [selectedControlType, setSelectedControlType] = useState(controlType); - const [controlEditorValid, setControlEditorValid] = useState(false); + const [editorState, setEditorState] = useState(initialState); + const [defaultPanelTitle, setDefaultPanelTitle] = useState( + initialState.defaultPanelTitle ?? initialState.fieldName ?? '' + ); + const [panelTitle, setPanelTitle] = useState(initialState.title ?? defaultPanelTitle); + const [selectedControlType, setSelectedControlType] = useState( + initialState.controlType + ); + const [controlEditorValid, setControlEditorValid] = useState(false); /** TODO: Make `editorConfig` work when refactoring the `ControlGroupRenderer` */ // const editorConfig = controlGroup.getEditorConfig(); @@ -169,7 +155,7 @@ export const DataControlEditor = ({ loading: dataViewListLoading, value: dataViewListItems = [], error: dataViewListError, - } = useAsync(() => { + } = useAsync(async () => { return dataViewService.getIdsWithTitle(); }); @@ -182,25 +168,26 @@ export const DataControlEditor = ({ }, error: fieldListError, } = useAsync(async () => { - if (!selectedDataViewId) { + if (!editorState.dataViewId) { return; } - const dataView = await dataViewService.get(selectedDataViewId); + + const dataView = await dataViewService.get(editorState.dataViewId); const registry = await getDataControlFieldRegistry(dataView); return { selectedDataView: dataView, fieldRegistry: registry, }; - }, [selectedDataViewId]); + }, [editorState.dataViewId]); useEffect(() => { setControlEditorValid( - Boolean(selectedFieldName) && Boolean(selectedDataView) && Boolean(selectedControlType) + Boolean(editorState.fieldName) && Boolean(selectedDataView) && Boolean(selectedControlType) ); - }, [selectedFieldName, setControlEditorValid, selectedDataView, selectedControlType]); + }, [editorState.fieldName, setControlEditorValid, selectedDataView, selectedControlType]); const CustomSettingsComponent = useMemo(() => { - if (!selectedControlType || !selectedFieldName || !fieldRegistry) return; + if (!selectedControlType || !editorState.fieldName || !fieldRegistry) return; const controlFactory = getControlFactory(selectedControlType) as DataControlFactory; const CustomSettings = controlFactory.CustomOptionsComponent; @@ -222,17 +209,21 @@ export const DataControlEditor = ({ )} data-test-subj="control-editor-custom-settings" > - + setEditorState({ ...editorState, ...newState })} + setControlEditorValid={setControlEditorValid} + /> ); - }, [fieldRegistry, selectedControlType, selectedFieldName, stateManager]); + }, [fieldRegistry, selectedControlType, editorState, initialState]); return ( <>

- {!controlType + {!initialState.controlId // if no ID, then we are creating a new control ? DataControlEditorStrings.manageControl.getFlyoutCreateTitle() : DataControlEditorStrings.manageControl.getFlyoutEditTitle()}

@@ -260,9 +251,9 @@ export const DataControlEditor = ({ ) : ( { - stateManager.dataViewId.next(newDataViewId); + setEditorState({ ...editorState, dataViewId: newDataViewId }); setSelectedControlType(undefined); }} trigger={{ @@ -292,15 +283,17 @@ export const DataControlEditor = ({ // const customPredicate = controlGroup.fieldFilterPredicate?.(field) ?? true; return Boolean(fieldRegistry?.[field.name]); }} - selectedFieldName={selectedFieldName} + selectedFieldName={editorState.fieldName} dataView={selectedDataView} onSelectField={(field) => { + setEditorState({ ...editorState, fieldName: field.name }); setSelectedControlType(fieldRegistry?.[field.name]?.compatibleControlTypes[0]); + const newDefaultTitle = field.displayName ?? field.name; - stateManager.fieldName.next(field.name); - setSelectedFieldDisplayName(newDefaultTitle); - if (!currentTitle || currentTitle === selectedFieldDisplayName) { - stateManager.title.next(newDefaultTitle); + setDefaultPanelTitle(newDefaultTitle); + const currentTitle = editorState.title; + if (!currentTitle || currentTitle === newDefaultTitle) { + setPanelTitle(newDefaultTitle); } }} selectableProps={{ isLoading: dataViewListLoading || dataViewLoading }} @@ -314,7 +307,7 @@ export const DataControlEditor = ({
@@ -333,9 +326,15 @@ export const DataControlEditor = ({ > stateManager.title.next(e.target.value)} + placeholder={defaultPanelTitle} + value={panelTitle} + onChange={(e) => { + setPanelTitle(e.target.value ?? ''); + setEditorState({ + ...editorState, + title: e.target.value === '' ? undefined : e.target.value, + }); + }} /> {/* {!editorConfig?.hideWidthSettings && ( */} @@ -347,18 +346,20 @@ export const DataControlEditor = ({ color="primary" legend={DataControlEditorStrings.management.controlWidth.getWidthSwitchLegend()} options={CONTROL_WIDTH_OPTIONS} - idSelected={selectedWidth ?? defaultWidth ?? DEFAULT_CONTROL_WIDTH} - onChange={(newWidth: string) => stateManager.width.next(newWidth as ControlWidth)} + idSelected={editorState.width ?? defaultWidth ?? DEFAULT_CONTROL_WIDTH} + onChange={(newWidth: string) => + setEditorState({ ...editorState, width: newWidth as ControlWidth }) + } /> stateManager.grow.next(!selectedGrow)} + onChange={() => setEditorState({ ...editorState, grow: !editorState.grow })} data-test-subj="control-editor-grow-switch" />
@@ -367,17 +368,17 @@ export const DataControlEditor = ({ {CustomSettingsComponent} {/* {!editorConfig?.hideAdditionalSettings ? CustomSettingsComponent : null} */} - {controlId && ( + {initialState.controlId && ( <> { - onCancel(); - controlGroup.removePanel(controlId); + onCancel(initialState); // don't want to show "lost changes" warning + controlGroup.removePanel(initialState.controlId!); }} > {DataControlEditorStrings.manageControl.getDeleteButtonTitle()} @@ -390,11 +391,11 @@ export const DataControlEditor = ({ { - onCancel(); + onCancel(editorState); }} > {DataControlEditorStrings.manageControl.getCancelTitle()} @@ -402,13 +403,13 @@ export const DataControlEditor = ({ { - onSave(); + onSave(editorState, selectedControlType!); }} > {DataControlEditorStrings.manageControl.getSaveChangesTitle()} diff --git a/examples/controls_example/public/react_controls/data_controls/initialize_data_control.tsx b/examples/controls_example/public/react_controls/data_controls/initialize_data_control.tsx index d3a2b20fc0d02..2f5babd94951d 100644 --- a/examples/controls_example/public/react_controls/data_controls/initialize_data_control.tsx +++ b/examples/controls_example/public/react_controls/data_controls/initialize_data_control.tsx @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import { isEqual } from 'lodash'; import { BehaviorSubject, combineLatest, switchMap } from 'rxjs'; import { CoreStart } from '@kbn/core-lifecycle-browser'; @@ -109,15 +110,46 @@ export const initializeDataControl = ( ); const onEdit = async () => { - openDataControlEditor( - { ...stateManager, ...editorStateManager } as ControlStateManager< - DefaultDataControlState & EditorState - >, - controlGroup, + // get the initial state from the state manager + const mergedStateManager = { + ...stateManager, + ...editorStateManager, + } as ControlStateManager; + const initialState = ( + Object.keys(mergedStateManager) as Array + ).reduce((prev, key) => { + return { + ...prev, + [key]: mergedStateManager[key]?.getValue(), + }; + }, {} as DefaultDataControlState & EditorState); + + // open the editor to get the new state + openDataControlEditor({ services, - controlType, - controlId - ); + onSave: ({ type: newType, state: newState }) => { + if (newType === controlType) { + // apply the changes from the new state via the state manager + (Object.keys(initialState) as Array).forEach( + (key) => { + if (!isEqual(mergedStateManager[key].getValue(), newState[key])) { + mergedStateManager[key].next(newState[key]); + } + } + ); + } else { + // replace the control with a new one of the updated type + controlGroup.replacePanel(controlId, { panelType: newType, initialState }); + } + }, + initialState: { + ...initialState, + controlType, + controlId, + defaultPanelTitle: defaultPanelTitle.getValue(), + }, + controlGroupApi: controlGroup, + }); }; const api: ControlApiInitialization = { diff --git a/examples/controls_example/public/react_controls/data_controls/mocks/data_control_mocks.tsx b/examples/controls_example/public/react_controls/data_controls/mocks/data_control_mocks.tsx new file mode 100644 index 0000000000000..dcb990a8d8419 --- /dev/null +++ b/examples/controls_example/public/react_controls/data_controls/mocks/data_control_mocks.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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; + +import { DataControlFactory } from '../types'; + +export const getMockedSearchControlFactory = (api: any) => + ({ + type: 'search', + getIconType: () => 'searchControlIcon', + getDisplayName: () => 'Search', + isFieldCompatible: (field) => + field.aggregatable && + field.searchable && + field.spec.type === 'string' && + (field.spec.esTypes ?? []).includes('text'), + buildControl: jest.fn().mockReturnValue({ + api, + Component: <>Search control component, + }), + } as DataControlFactory); + +export const getMockedOptionsListControlFactory = (api: any) => + ({ + type: 'optionsList', + getIconType: () => 'optionsListIcon', + getDisplayName: () => 'Options list', + isFieldCompatible: (field) => + field.aggregatable && + !field.spec.scripted && + ['string', 'boolean', 'ip', 'date', 'number'].includes(field.type), + buildControl: jest.fn().mockReturnValue({ + api, + Component: <>Options list component, + }), + CustomOptionsComponent: () => ( +
Custom options list component
+ ), + } as DataControlFactory); + +export const getMockedRangeSliderControlFactory = (api: any) => + ({ + type: 'rangeSlider', + getIconType: () => 'rangeSliderIcon', + getDisplayName: () => 'Range slider', + isFieldCompatible: (field) => field.aggregatable && field.type === 'number', + buildControl: jest.fn().mockReturnValue({ + api, + Component: <>Range slider component, + }), + } as DataControlFactory); diff --git a/examples/controls_example/public/react_controls/data_controls/open_data_control_editor.tsx b/examples/controls_example/public/react_controls/data_controls/open_data_control_editor.tsx index 5c25ffcc7947d..3c16183b18434 100644 --- a/examples/controls_example/public/react_controls/data_controls/open_data_control_editor.tsx +++ b/examples/controls_example/public/react_controls/data_controls/open_data_control_editor.tsx @@ -8,7 +8,6 @@ import React from 'react'; import deepEqual from 'react-fast-compare'; -import { BehaviorSubject } from 'rxjs'; import { CoreStart, OverlayRef } from '@kbn/core/public'; import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; @@ -20,112 +19,92 @@ import { toMountPoint } from '@kbn/react-kibana-mount'; import { ControlGroupApi } from '../control_group/types'; import { DataControlEditor } from './data_control_editor'; import { DefaultDataControlState } from './types'; -import { ControlStateManager } from '../types'; -export const openDataControlEditor = async < - State extends DefaultDataControlState = DefaultDataControlState ->( - stateManager: ControlStateManager, - controlGroupApi: ControlGroupApi, +export type DataControlEditorState = Omit & { + fieldName?: string; + controlType?: string; + controlId?: string; + defaultPanelTitle?: string; +}; + +export const openDataControlEditor = < + State extends DataControlEditorState = DataControlEditorState +>({ + initialState, + onSave, + controlGroupApi, + services, +}: { + initialState: State; + onSave: ({ type, state }: { type: string; state: State }) => void; + controlGroupApi: ControlGroupApi; services: { core: CoreStart; dataViews: DataViewsPublicPluginStart; - }, - controlType?: string, - controlId?: string -): Promise => { - return new Promise((resolve) => { - /** - * Duplicate all state into a new manager because we do not want to actually apply the changes - * to the control until the user hits save. - */ - const editorStateManager: ControlStateManager = Object.keys(stateManager).reduce( - (prev, key) => { - return { - ...prev, - [key as keyof State]: new BehaviorSubject(stateManager[key as keyof State].getValue()), - }; - }, - {} as ControlStateManager - ); - - const closeOverlay = (overlayRef: OverlayRef) => { - if (apiHasParentApi(controlGroupApi) && tracksOverlays(controlGroupApi.parentApi)) { - controlGroupApi.parentApi.clearOverlays(); - } - overlayRef.close(); - }; - - const onCancel = (overlay: OverlayRef) => { - const initialState = Object.keys(stateManager).map((key) => { - return stateManager[key as keyof State].getValue(); - }); - const newState = Object.keys(editorStateManager).map((key) => { - return editorStateManager[key as keyof State].getValue(); - }); - - if (deepEqual(initialState, newState)) { - closeOverlay(overlay); - return; - } - services.core.overlays - .openConfirm( - i18n.translate('controls.controlGroup.management.discard.sub', { - defaultMessage: `Changes that you've made to this control will be discarded, are you sure you want to continue?`, - }), - { - confirmButtonText: i18n.translate('controls.controlGroup.management.discard.confirm', { - defaultMessage: 'Discard changes', - }), - cancelButtonText: i18n.translate('controls.controlGroup.management.discard.cancel', { - defaultMessage: 'Cancel', - }), - title: i18n.translate('controls.controlGroup.management.discard.title', { - defaultMessage: 'Discard changes?', - }), - buttonColor: 'danger', - } - ) - .then((confirmed) => { - if (confirmed) { - closeOverlay(overlay); - } - }); - }; + }; +}): void => { + const closeOverlay = (overlayRef: OverlayRef) => { + if (apiHasParentApi(controlGroupApi) && tracksOverlays(controlGroupApi.parentApi)) { + controlGroupApi.parentApi.clearOverlays(); + } + overlayRef.close(); + }; - const overlay = services.core.overlays.openFlyout( - toMountPoint( - { - onCancel(overlay); - }} - onSave={() => { - Object.keys(stateManager).forEach((key) => { - stateManager[key as keyof State].next( - editorStateManager[key as keyof State].getValue() - ); - }); - closeOverlay(overlay); - resolve(undefined); - }} - stateManager={editorStateManager} - services={{ dataViews: services.dataViews }} - />, + const onCancel = (newState: State, overlay: OverlayRef) => { + if (deepEqual(initialState, newState)) { + closeOverlay(overlay); + return; + } + services.core.overlays + .openConfirm( + i18n.translate('controls.controlGroup.management.discard.sub', { + defaultMessage: `Changes that you've made to this control will be discarded, are you sure you want to continue?`, + }), { - theme: services.core.theme, - i18n: services.core.i18n, + confirmButtonText: i18n.translate('controls.controlGroup.management.discard.confirm', { + defaultMessage: 'Discard changes', + }), + cancelButtonText: i18n.translate('controls.controlGroup.management.discard.cancel', { + defaultMessage: 'Cancel', + }), + title: i18n.translate('controls.controlGroup.management.discard.title', { + defaultMessage: 'Discard changes?', + }), + buttonColor: 'danger', + } + ) + .then((confirmed) => { + if (confirmed) { + closeOverlay(overlay); } - ), + }); + }; + + const overlay = services.core.overlays.openFlyout( + toMountPoint( + + parentApi={controlGroupApi} + initialState={initialState} + onCancel={(state) => { + onCancel(state, overlay); + }} + onSave={(state, selectedControlType) => { + closeOverlay(overlay); + onSave({ type: selectedControlType, state }); + }} + services={{ dataViews: services.dataViews }} + />, { - onClose: () => closeOverlay(overlay), + theme: services.core.theme, + i18n: services.core.i18n, } - ); - - if (apiHasParentApi(controlGroupApi) && tracksOverlays(controlGroupApi.parentApi)) { - controlGroupApi.parentApi.openOverlay(overlay); + ), + { + onClose: () => closeOverlay(overlay), } - }); + ); + + if (apiHasParentApi(controlGroupApi) && tracksOverlays(controlGroupApi.parentApi)) { + controlGroupApi.parentApi.openOverlay(overlay); + } }; diff --git a/examples/controls_example/public/react_controls/data_controls/range_slider/components/range_slider.scss b/examples/controls_example/public/react_controls/data_controls/range_slider/components/range_slider.scss index 344ba87dc6f73..5472ef81dd299 100644 --- a/examples/controls_example/public/react_controls/data_controls/range_slider/components/range_slider.scss +++ b/examples/controls_example/public/react_controls/data_controls/range_slider/components/range_slider.scss @@ -22,8 +22,10 @@ } .rangeSliderAnchor__fieldNumber { + min-width: auto !important; font-weight: $euiFontWeightMedium; height: calc($euiButtonHeight - 3px) !important; + background-color: transparent !important; &.rangeSliderAnchor__fieldNumber--valid:invalid:not(:focus) { background-image: none; // override the red underline for values between steps diff --git a/examples/controls_example/public/react_controls/data_controls/range_slider/components/range_slider_control.tsx b/examples/controls_example/public/react_controls/data_controls/range_slider/components/range_slider_control.tsx index 74ac8c2f20a8e..f52dd0c3e528b 100644 --- a/examples/controls_example/public/react_controls/data_controls/range_slider/components/range_slider_control.tsx +++ b/examples/controls_example/public/react_controls/data_controls/range_slider/components/range_slider_control.tsx @@ -24,6 +24,7 @@ interface Props { step: number | undefined; value: RangeValue | undefined; uuid: string; + controlPanelClassName?: string; } export const RangeSliderControl: FC = ({ @@ -36,7 +37,7 @@ export const RangeSliderControl: FC = ({ step, value, uuid, - ...rest + controlPanelClassName, }: Props) => { const rangeSliderRef = useRef(null); @@ -179,7 +180,7 @@ export const RangeSliderControl: FC = ({ max={displayedMax} isLoading={isLoading} inputPopoverProps={{ - ...rest, + className: controlPanelClassName, panelMinWidth: MIN_POPOVER_WIDTH, }} append={ diff --git a/examples/controls_example/public/react_controls/data_controls/range_slider/get_range_slider_control_factory.test.tsx b/examples/controls_example/public/react_controls/data_controls/range_slider/get_range_slider_control_factory.test.tsx index 457796f1c028f..73aa593c0ce56 100644 --- a/examples/controls_example/public/react_controls/data_controls/range_slider/get_range_slider_control_factory.test.tsx +++ b/examples/controls_example/public/react_controls/data_controls/range_slider/get_range_slider_control_factory.test.tsx @@ -7,20 +7,22 @@ */ import React from 'react'; -import { estypes } from '@elastic/elasticsearch'; -import { TimeRange } from '@kbn/es-query'; import { BehaviorSubject, first, of, skip } from 'rxjs'; -import { render, waitFor } from '@testing-library/react'; + +import { estypes } from '@elastic/elasticsearch'; import { coreMock } from '@kbn/core/public/mocks'; import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; -import { ControlGroupApi } from '../../control_group/types'; -import { getRangesliderControlFactory } from './get_range_slider_control_factory'; import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; -import { ControlApiRegistration } from '../../types'; -import { RangesliderControlApi, RangesliderControlState } from './types'; -import { StateComparators } from '@kbn/presentation-publishing'; +import { TimeRange } from '@kbn/es-query'; import { SerializedPanelState } from '@kbn/presentation-containers'; +import { StateComparators } from '@kbn/presentation-publishing'; +import { fireEvent, render, waitFor } from '@testing-library/react'; + import { ControlFetchContext } from '../../control_group/control_fetch'; +import { ControlGroupApi } from '../../control_group/types'; +import { ControlApiRegistration } from '../../types'; +import { getRangesliderControlFactory } from './get_range_slider_control_factory'; +import { RangesliderControlApi, RangesliderControlState } from './types'; const DEFAULT_TOTAL_RESULTS = 20; const DEFAULT_MIN = 0; @@ -182,7 +184,7 @@ describe('RangesliderControlApi', () => { uuid, controlGroupApi ); - const { findByTestId } = render(); + const { findByTestId } = render(); await waitFor(async () => { await findByTestId('range-slider-control-invalid-append-myControl1'); }); @@ -200,7 +202,7 @@ describe('RangesliderControlApi', () => { uuid, controlGroupApi ); - const { findByTestId } = render(); + const { findByTestId } = render(); await waitFor(async () => { const minInput = await findByTestId('rangeSlider__lowerBoundFieldNumber'); expect(minInput).toHaveAttribute('placeholder', String(DEFAULT_MIN)); @@ -240,4 +242,53 @@ describe('RangesliderControlApi', () => { expect(serializedState.rawState.step).toBe(1024); }); }); + + describe('custom options component', () => { + test('defaults to step size of 1', async () => { + const CustomSettings = factory.CustomOptionsComponent!; + const component = render( + + ); + expect( + component.getByTestId('rangeSliderControl__stepAdditionalSetting').getAttribute('value') + ).toBe('1'); + }); + + test('validates step setting is greater than 0', async () => { + const setControlEditorValid = jest.fn(); + const CustomSettings = factory.CustomOptionsComponent!; + const component = render( + + ); + + fireEvent.change(component.getByTestId('rangeSliderControl__stepAdditionalSetting'), { + target: { valueAsNumber: -1 }, + }); + expect(setControlEditorValid).toBeCalledWith(false); + fireEvent.change(component.getByTestId('rangeSliderControl__stepAdditionalSetting'), { + target: { value: '' }, + }); + expect(setControlEditorValid).toBeCalledWith(false); + fireEvent.change(component.getByTestId('rangeSliderControl__stepAdditionalSetting'), { + target: { valueAsNumber: 0 }, + }); + expect(setControlEditorValid).toBeCalledWith(false); + fireEvent.change(component.getByTestId('rangeSliderControl__stepAdditionalSetting'), { + target: { valueAsNumber: 0.5 }, + }); + expect(setControlEditorValid).toBeCalledWith(true); + fireEvent.change(component.getByTestId('rangeSliderControl__stepAdditionalSetting'), { + target: { valueAsNumber: 10 }, + }); + expect(setControlEditorValid).toBeCalledWith(true); + }); + }); }); diff --git a/examples/controls_example/public/react_controls/data_controls/range_slider/get_range_slider_control_factory.tsx b/examples/controls_example/public/react_controls/data_controls/range_slider/get_range_slider_control_factory.tsx index 602fc31721f5e..ed882873f73a7 100644 --- a/examples/controls_example/public/react_controls/data_controls/range_slider/get_range_slider_control_factory.tsx +++ b/examples/controls_example/public/react_controls/data_controls/range_slider/get_range_slider_control_factory.tsx @@ -6,17 +6,20 @@ * Side Public License, v 1. */ -import React, { useEffect, useMemo } from 'react'; +import React, { useEffect, useMemo, useState } from 'react'; import deepEqual from 'react-fast-compare'; -import { BehaviorSubject, combineLatest, distinctUntilChanged, map, skip } from 'rxjs'; + import { EuiFieldNumber, EuiFormRow } from '@elastic/eui'; -import { - useBatchedPublishingSubjects, - useStateFromPublishingSubject, -} from '@kbn/presentation-publishing'; import { buildRangeFilter, Filter, RangeFilterParams } from '@kbn/es-query'; +import { useBatchedPublishingSubjects } from '@kbn/presentation-publishing'; + +import { BehaviorSubject, combineLatest, distinctUntilChanged, map, skip } from 'rxjs'; import { initializeDataControl } from '../initialize_data_control'; import { DataControlFactory } from '../types'; +import { RangeSliderControl } from './components/range_slider_control'; +import { hasNoResults$ } from './has_no_results'; +import { minMax$ } from './min_max'; +import { RangeSliderStrings } from './range_slider_strings'; import { RangesliderControlApi, RangesliderControlState, @@ -24,10 +27,6 @@ import { RANGE_SLIDER_CONTROL_TYPE, Services, } from './types'; -import { RangeSliderStrings } from './range_slider_strings'; -import { RangeSliderControl } from './components/range_slider_control'; -import { minMax$ } from './min_max'; -import { hasNoResults$ } from './has_no_results'; export const getRangesliderControlFactory = ( services: Services @@ -39,8 +38,8 @@ export const getRangesliderControlFactory = ( isFieldCompatible: (field) => { return field.aggregatable && field.type === 'number'; }, - CustomOptionsComponent: ({ stateManager, setControlEditorValid }) => { - const step = useStateFromPublishingSubject(stateManager.step); + CustomOptionsComponent: ({ initialState, updateState, setControlEditorValid }) => { + const [step, setStep] = useState(initialState.step ?? 1); return ( <> @@ -49,7 +48,8 @@ export const getRangesliderControlFactory = ( value={step} onChange={(event) => { const newStep = event.target.valueAsNumber; - stateManager.step.next(newStep); + setStep(newStep); + updateState({ step: newStep }); setControlEditorValid(newStep > 0); }} min={0} @@ -210,7 +210,7 @@ export const getRangesliderControlFactory = ( return { api, - Component: (controlPanelClassNames) => { + Component: ({ className: controlPanelClassName }) => { const [dataLoading, dataViews, fieldName, max, min, selectionHasNotResults, step, value] = useBatchedPublishingSubjects( dataLoading$, @@ -246,7 +246,7 @@ export const getRangesliderControlFactory = ( return ( { - const searchTechnique = useStateFromPublishingSubject(stateManager.searchTechnique); + CustomOptionsComponent: ({ initialState, updateState }) => { + const [searchTechnique, setSearchTechnique] = useState(initialState.searchTechnique); return ( @@ -73,7 +75,8 @@ export const getSearchControlFactory = ({ idSelected={searchTechnique ?? DEFAULT_SEARCH_TECHNIQUE} onChange={(id) => { const newSearchTechnique = id as SearchControlTechniques; - stateManager.searchTechnique.next(newSearchTechnique); + setSearchTechnique(newSearchTechnique); + updateState({ searchTechnique: newSearchTechnique }); }} /> @@ -188,7 +191,7 @@ export const getSearchControlFactory = ({ * The `controlPanelClassNamess` prop is necessary because it contains the class names from the generic * ControlPanel that are necessary for styling */ - Component: (controlPanelClassNames) => { + Component: ({ className: controlPanelClassName }) => { const currentSearch = useStateFromPublishingSubject(searchString); useEffect(() => { @@ -202,7 +205,10 @@ export const getSearchControlFactory = ({ return ( & // control titles cannot be hidden @@ -35,7 +30,8 @@ export interface DataControlFactory< > extends ControlFactory { isFieldCompatible: (field: DataViewField) => boolean; CustomOptionsComponent?: React.FC<{ - stateManager: ControlStateManager; + initialState: Omit; + updateState: (newState: Partial) => void; setControlEditorValid: (valid: boolean) => void; }>; } diff --git a/examples/controls_example/public/react_controls/types.ts b/examples/controls_example/public/react_controls/types.ts index bbbd7584e2049..8d8c7f7a8e89a 100644 --- a/examples/controls_example/public/react_controls/types.ts +++ b/examples/controls_example/public/react_controls/types.ts @@ -85,7 +85,7 @@ export interface ControlFactory< ) => ControlApi, uuid: string, parentApi: ControlGroupApi - ) => { api: ControlApi; Component: React.FC<{}> }; + ) => { api: ControlApi; Component: React.FC<{ className: string }> }; } export type ControlStateManager = { diff --git a/examples/controls_example/tsconfig.json b/examples/controls_example/tsconfig.json index 76ff8d8a75f03..cc7905c5e5270 100644 --- a/examples/controls_example/tsconfig.json +++ b/examples/controls_example/tsconfig.json @@ -34,5 +34,6 @@ "@kbn/core-lifecycle-browser", "@kbn/presentation-panel-plugin", "@kbn/datemath", + "@kbn/ui-theme", ] } diff --git a/examples/feature_control_examples/server/plugin.ts b/examples/feature_control_examples/server/plugin.ts index 6ee81333d0c00..8028d46afc4ac 100644 --- a/examples/feature_control_examples/server/plugin.ts +++ b/examples/feature_control_examples/server/plugin.ts @@ -8,7 +8,7 @@ import { CoreSetup, DEFAULT_APP_CATEGORIES, Plugin } from '@kbn/core/server'; import { - PluginSetupContract as FeaturesPluginSetup, + FeaturesPluginSetup, // PluginStartContract as FeaturesPluginStart, } from '@kbn/features-plugin/server'; import { FEATURE_PRIVILEGES_PLUGIN_ID } from '../common'; diff --git a/examples/user_profile_examples/server/plugin.ts b/examples/user_profile_examples/server/plugin.ts index 0cc411be1121e..7cf378b769bfa 100644 --- a/examples/user_profile_examples/server/plugin.ts +++ b/examples/user_profile_examples/server/plugin.ts @@ -7,10 +7,7 @@ */ import type { Plugin, CoreSetup } from '@kbn/core/server'; -import { - PluginSetupContract as FeaturesPluginSetup, - PluginStartContract as FeaturesPluginStart, -} from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup, FeaturesPluginStart } from '@kbn/features-plugin/server'; import { SecurityPluginSetup, SecurityPluginStart } from '@kbn/security-plugin/server'; import { SpacesPluginSetup, SpacesPluginStart } from '@kbn/spaces-plugin/server'; import { schema } from '@kbn/config-schema'; diff --git a/oas_docs/.spectral.yaml b/oas_docs/.spectral.yaml index b328e320e23eb..7ed4b0fe0d725 100644 --- a/oas_docs/.spectral.yaml +++ b/oas_docs/.spectral.yaml @@ -14,9 +14,9 @@ rules: oas3-valid-schema-example: false oas2-valid-media-example: false # Operations - operation-operationId: false - operation-operationId-unique: false - operation-operationId-valid-in-url: false + operation-operationId: warn + operation-operationId-unique: warn + operation-operationId-valid-in-url: warn operation-tag-defined: warn operation-tags: warn # Responses diff --git a/oas_docs/README.md b/oas_docs/README.md index 70e39571c0af6..a140d409e77a3 100644 --- a/oas_docs/README.md +++ b/oas_docs/README.md @@ -1,4 +1,7 @@ The `bundle.json` and `bundle.serverless.json` files are generated automatically. -The `kibana.openapi.serverless.yaml` file is a temporary OpenAPI document created by joining some manually-maintained files. -To create it and lint it, run `make api-docs` and `make api-docs-lint`. \ No newline at end of file +The `output/kibana.serverless.yaml` file is a temporary OpenAPI document created by joining some manually-maintained files. +To create it and lint it, run `make api-docs` or `make api-docs-serverless` and `make api-docs-lint` or `make api-docs-lint-serverless`. + +The `output/kibana.yaml` file is a temporary OpenAPI document created by joining some manually-maintained files. +To create it and lint it, run `make api-docs` or `make api-docs-stateful` and `make api-docs-lint` or `make api-docs-lint-stateful`. \ No newline at end of file diff --git a/oas_docs/kibana.info.serverless.yaml b/oas_docs/kibana.info.serverless.yaml index c96325cf7c75d..09322f0851847 100644 --- a/oas_docs/kibana.info.serverless.yaml +++ b/oas_docs/kibana.info.serverless.yaml @@ -2,6 +2,10 @@ openapi: 3.0.3 info: title: Kibana Serverless APIs description: | + **Technical preview** + 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. + The Kibana REST APIs for Elastic serverless enable you to manage resources such as connectors, data views, and saved objects. The API calls are stateless. Each request that you make happens in isolation from other calls diff --git a/oas_docs/kibana.info.yaml b/oas_docs/kibana.info.yaml new file mode 100644 index 0000000000000..888d9aaef86c3 --- /dev/null +++ b/oas_docs/kibana.info.yaml @@ -0,0 +1,47 @@ +openapi: 3.0.3 +info: + title: Kibana APIs + description: | + The Kibana REST APIs enable you to manage resources such as connectors, data views, and saved objects. + The API calls are stateless. + Each request that you make happens in isolation from other calls and must include all of the necessary information for Kibana to fulfill the + request. + API requests return JSON output, which is a format that is machine-readable and works well for automation. + + To interact with Kibana APIs, use the following operations: + + - GET: Fetches the information. + - PATCH: Applies partial modifications to the existing information. + - POST: Adds new information. + - PUT: Updates the existing information. + - DELETE: Removes the information. + + You can prepend any Kibana API endpoint with `kbn:` and run the request in **Dev Tools → Console**. + For example: + + ``` + GET kbn:/api/data_views + ``` + version: "1.0.2" + license: + name: Elastic License 2.0 + url: https://www.elastic.co/licensing/elastic-license + contact: + name: Kibana Team +# servers: +# - url: https://{kibana_url} +# variables: +# kibana_url: +# default: localhost:5601 +# security: +# - apiKeyAuth: [] +# components: +# securitySchemes: +# apiKeyAuth: +# type: apiKey +# in: header +# name: Authorization +# description: > +# These APIs use key-based authentication. +# You must create an API key and use the encoded value in the request header. +# For example: `Authorization: ApiKey base64AccessApiKey` \ No newline at end of file diff --git a/oas_docs/makefile b/oas_docs/makefile index da353781351b0..c356535a34ed1 100644 --- a/oas_docs/makefile +++ b/oas_docs/makefile @@ -14,12 +14,36 @@ # permission is obtained from Elasticsearch B.V. .PHONY: api-docs -api-docs: ## Generate kibana.serverless.yaml - @npx @redocly/cli join "kibana.info.serverless.yaml" "../x-pack/plugins/observability_solution/apm/docs/openapi/apm.yaml" "../x-pack/plugins/actions/docs/openapi/bundled_serverless.yaml" "../src/plugins/data_views/docs/openapi/bundled.yaml" "../x-pack/plugins/ml/common/openapi/ml_apis_serverless.yaml" "../packages/core/saved-objects/docs/openapi/bundled_serverless.yaml" "../x-pack/plugins/observability_solution/slo/docs/openapi/slo/bundled.yaml" -o "kibana.serverless.yaml" --prefix-components-with-info-prop title +api-docs: ## Generate kibana.serverless.yaml and kibana.yaml + @npx @redocly/cli join "kibana.info.serverless.yaml" "../x-pack/plugins/observability_solution/apm/docs/openapi/apm.yaml" "../x-pack/plugins/actions/docs/openapi/bundled_serverless.yaml" "../src/plugins/data_views/docs/openapi/bundled.yaml" "../x-pack/plugins/ml/common/openapi/ml_apis_serverless.yaml" "../packages/core/saved-objects/docs/openapi/bundled_serverless.yaml" "../x-pack/plugins/observability_solution/slo/docs/openapi/slo/bundled.yaml" -o "output/kibana.serverless.yaml" --prefix-components-with-info-prop title + @npx @redocly/cli join "kibana.info.yaml" "../x-pack/plugins/observability_solution/apm/docs/openapi/apm.yaml" "../x-pack/plugins/actions/docs/openapi/bundled.yaml" "../src/plugins/data_views/docs/openapi/bundled.yaml" "../x-pack/plugins/ml/common/openapi/ml_apis.yaml" "../packages/core/saved-objects/docs/openapi/bundled.yaml" "../x-pack/plugins/observability_solution/slo/docs/openapi/slo/bundled.yaml" -o "output/kibana.yaml" --prefix-components-with-info-prop title +.PHONY: api-docs-stateful +api-docs-stateful: ## Generate only kibana.yaml + @npx @redocly/cli join "kibana.info.yaml" "../x-pack/plugins/observability_solution/apm/docs/openapi/apm.yaml" "../x-pack/plugins/actions/docs/openapi/bundled.yaml" "../src/plugins/data_views/docs/openapi/bundled.yaml" "../x-pack/plugins/ml/common/openapi/ml_apis.yaml" "../packages/core/saved-objects/docs/openapi/bundled.yaml" "../x-pack/plugins/observability_solution/slo/docs/openapi/slo/bundled.yaml" -o "output/kibana.yaml" --prefix-components-with-info-prop title +# Temporarily omit "../x-pack/plugins/alerting/docs/openapi/bundled.yaml" and "../x-pack/plugins/cases/docs/openapi/bundled.yaml" due to OAS version +# Temporarily omit "../x-pack/plugins/fleet/common/openapi/bundled.yaml" due to internals tag and tag sorting + +.PHONY: api-docs-serverless +api-docs-serverless: ## Generate only kibana.serverless.yaml + @npx @redocly/cli join "kibana.info.serverless.yaml" "../x-pack/plugins/observability_solution/apm/docs/openapi/apm.yaml" "../x-pack/plugins/actions/docs/openapi/bundled_serverless.yaml" "../src/plugins/data_views/docs/openapi/bundled.yaml" "../x-pack/plugins/ml/common/openapi/ml_apis_serverless.yaml" "../packages/core/saved-objects/docs/openapi/bundled_serverless.yaml" "../x-pack/plugins/observability_solution/slo/docs/openapi/slo/bundled.yaml" -o "output/kibana.serverless.yaml" --prefix-components-with-info-prop title + .PHONY: api-docs-lint -api-docs-lint: ## Run spectral API docs linter - @npx @stoplight/spectral-cli lint "kibana.serverless.yaml" --ruleset ".spectral.yaml" +api-docs-lint: ## Run spectral API docs linter + @npx @stoplight/spectral-cli lint "output/kibana.serverless.yaml" --ruleset ".spectral.yaml" + @npx @stoplight/spectral-cli lint "output/kibana.yaml" --ruleset ".spectral.yaml" + +.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" + +.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" + +.PHONY: api-docs-overlay-stateful +api-docs-overlay-stateful: ## Run spectral API docs linter on kibana.serverless.yaml + @npx bump overlay "output/kibana.yaml" "overlays/kibana.overlays.yaml" > "output/kibana.new.yaml" help: ## Display help @awk 'BEGIN {FS = ":.*##"; printf "Usage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) diff --git a/oas_docs/kibana.serverless.yaml b/oas_docs/output/kibana.serverless.yaml similarity index 99% rename from oas_docs/kibana.serverless.yaml rename to oas_docs/output/kibana.serverless.yaml index 24cf6df24a4d4..eb89ee566c709 100644 --- a/oas_docs/kibana.serverless.yaml +++ b/oas_docs/output/kibana.serverless.yaml @@ -1,26 +1,50 @@ openapi: 3.0.3 info: title: Kibana Serverless APIs - description: | + description: > + **Technical preview** + + 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. + + The Kibana REST APIs for Elastic serverless enable you to manage resources + such as connectors, data views, and saved objects. The API calls are + stateless. Each request that you make happens in isolation from other calls + and must include all of the necessary information for Kibana to fulfill the + request. API requests return JSON output, which is a format that is + machine-readable and works well for automation. + To interact with Kibana APIs, use the following operations: + - GET: Fetches the information. + - POST: Adds new information. + - PUT: Updates the existing information. + - DELETE: Removes the information. + You can prepend any Kibana API endpoint with `kbn:` and run the request in + **Dev Tools → Console**. For example: + ``` + GET kbn:/api/data_views + ``` version: 1.0.2 license: @@ -76,6 +100,7 @@ paths: post: summary: Create an APM agent key description: Create a new agent key for APM. + operationId: createAgentKey tags: - APM agent keys requestBody: @@ -117,6 +142,7 @@ paths: get: summary: Search for annotations description: Search for annotations related to a specific service. + operationId: getAnnotation tags: - APM annotations parameters: @@ -171,6 +197,7 @@ paths: post: summary: Create a service annotation description: Create a new annotation for a specific service. + operationId: createAnnotation tags: - APM annotations parameters: @@ -1246,13 +1273,13 @@ paths: summary: Update data view fields metadata in the default space operationId: updateFieldsMetadataDefault description: > - Update fields presentation metadata such as count, customLabel and - format. 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. You can update multiple fields in one request. - Updates are merged with persisted metadata. To remove existing metadata, - specify null as the value. + Update fields presentation metadata such as count, customLabel, + customDescription, and format. 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. You can update + multiple fields in one request. Updates are merged with persisted + metadata. To remove existing metadata, specify null as the value. tags: - data views parameters: @@ -3324,7 +3351,7 @@ components: description: > The generative artificial intelligence model for Amazon Bedrock to use. Current support is for the Anthropic Claude models. - default: anthropic.claude-3-sonnet-20240229-v1:0 + default: anthropic.claude-3-5-sonnet-20240620-v1:0 Connectors_secrets_properties_bedrock: title: Connector secrets properties for an Amazon Bedrock connector description: Defines secrets for connectors when type is `.bedrock`. @@ -3356,7 +3383,7 @@ components: description: >- The generative artificial intelligence model for Google Gemini to use. - default: gemini-1.5-pro-preview-0409 + default: gemini-1.5-pro-001 gcpRegion: type: string description: The GCP region where the Vertex AI endpoint enabled. @@ -3594,7 +3621,7 @@ components: The host name of the service provider. If the `service` is `elastic_cloud` (for Elastic Cloud notifications) or one of Nodemailer's well-known email service providers, this property is - ignored. If `service` is `other`, this property must be defined. + ignored. If `service` is `other`, this property must be defined. type: string oauthTokenUrl: type: string @@ -3604,7 +3631,7 @@ components: The port to connect to on the service provider. If the `service` is `elastic_cloud` (for Elastic Cloud notifications) or one of Nodemailer's well-known email service providers, this property is - ignored. If `service` is `other`, this property must be defined. + ignored. If `service` is `other`, this property must be defined. type: integer secure: description: > @@ -5272,7 +5299,7 @@ components: type: boolean description: > Indicates whether it is a preconfigured connector. If true, the `config` - and `is_missing_secrets` properties are omitted from the response. + and `is_missing_secrets` properties are omitted from the response. example: false Connectors_is_system_action: type: boolean @@ -5780,6 +5807,17 @@ components: Data_views_fieldattrs: type: object description: A map of field attributes by field name. + properties: + count: + type: integer + description: Popularity count for the field. + customDescription: + type: string + description: Custom description for the field. + maxLength: 300 + customLabel: + type: string + description: Custom label for the field. Data_views_fieldformats: type: object description: A map of field formats by field name. @@ -5835,7 +5873,9 @@ components: allowNoIndex: $ref: '#/components/schemas/Data_views_allownoindex' fieldAttrs: - $ref: '#/components/schemas/Data_views_fieldattrs' + type: object + additionalProperties: + $ref: '#/components/schemas/Data_views_fieldattrs' fieldFormats: $ref: '#/components/schemas/Data_views_fieldformats' fields: @@ -5877,7 +5917,9 @@ components: allowNoIndex: $ref: '#/components/schemas/Data_views_allownoindex' fieldAttrs: - $ref: '#/components/schemas/Data_views_fieldattrs' + type: object + additionalProperties: + $ref: '#/components/schemas/Data_views_fieldattrs' fieldFormats: $ref: '#/components/schemas/Data_views_fieldformats' fields: @@ -8594,11 +8636,15 @@ components: data_view_id: ff959d40-b880-11e8-a6d9-e546fe2bba5f force: true Data_views_update_field_metadata_request: - summary: Set popularity count for field foo. + summary: Update multiple metadata fields. value: fields: - foo: + field1: count: 123 + customLabel: Field 1 label + field2: + customLabel: Field 2 label + customDescription: Field 2 description Data_views_create_runtime_field_request: summary: Create a runtime field. value: diff --git a/oas_docs/output/kibana.yaml b/oas_docs/output/kibana.yaml new file mode 100644 index 0000000000000..517560f36c779 --- /dev/null +++ b/oas_docs/output/kibana.yaml @@ -0,0 +1,12058 @@ +openapi: 3.0.3 +info: + title: Kibana APIs + description: > + The Kibana REST APIs enable you to manage resources such as connectors, data + views, and saved objects. + + The API calls are stateless. + + Each request that you make happens in isolation from other calls and must + include all of the necessary information for Kibana to fulfill the + + request. + + API requests return JSON output, which is a format that is machine-readable + and works well for automation. + + + To interact with Kibana APIs, use the following operations: + + + - GET: Fetches the information. + + - PATCH: Applies partial modifications to the existing information. + + - POST: Adds new information. + + - PUT: Updates the existing information. + + - DELETE: Removes the information. + + + You can prepend any Kibana API endpoint with `kbn:` and run the request in + **Dev Tools → Console**. + + For example: + + + ``` + + GET kbn:/api/data_views + + ``` + version: 1.0.2 + license: + name: Elastic License 2.0 + url: https://www.elastic.co/licensing/elastic-license + contact: + name: Kibana Team +servers: + - url: / + - url: https://{kibana_url} + variables: + kibana_url: + default: localhost:5601 + - url: http://localhost:5601 + description: local +tags: + - name: APM agent keys + description: > + Configure APM agent keys to authorize requests from APM agents to the APM + Server. + x-displayName: APM agent keys + - name: APM annotations + description: > + Annotate visualizations in the APM app with significant events. + Annotations enable you to easily see how events are impacting the + performance of your applications. + x-displayName: APM annotations + - name: connectors + description: Connector APIs enable you to create and manage connectors. + x-displayName: connectors + - name: data views + description: >- + Data view APIs enable you to manage data views, formerly known as Kibana + index patterns. + x-displayName: data views + - name: ml + description: Machine learning + x-displayName: ml + - name: saved objects + description: >- + Manage Kibana saved objects, including dashboards, visualizations, and + more. + x-displayName: saved objects + - name: slo + description: SLO APIs enable you to define, manage and track service-level objectives + x-displayName: slo +paths: + /api/apm/agent_keys: + post: + summary: Create an APM agent key + description: Create a new agent key for APM. + operationId: createAgentKey + tags: + - APM agent keys + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + name: + type: string + privileges: + type: array + items: + type: string + enum: + - event:write + - config_agent:read + responses: + '200': + description: Agent key created successfully + content: + application/json: + schema: + type: object + properties: + api_key: + type: string + expiration: + type: integer + format: int64 + id: + type: string + name: + type: string + encoded: + type: string + /api/apm/services/{serviceName}/annotation/search: + get: + summary: Search for annotations + description: Search for annotations related to a specific service. + operationId: getAnnotation + tags: + - APM annotations + parameters: + - name: serviceName + in: path + required: true + description: The name of the service + schema: + type: string + - name: environment + in: query + required: false + description: The environment to filter annotations by + schema: + type: string + - name: start + in: query + required: false + description: The start date for the search + schema: + type: string + - name: end + in: query + required: false + description: The end date for the search + schema: + type: string + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + properties: + annotations: + type: array + items: + type: object + properties: + type: + type: string + enum: + - version + id: + type: string + '@timestamp': + type: number + text: + type: string + /api/apm/services/{serviceName}/annotation: + post: + summary: Create a service annotation + description: Create a new annotation for a specific service. + operationId: createAnnotation + tags: + - APM annotations + parameters: + - name: serviceName + in: path + required: true + description: The name of the service + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + '@timestamp': + type: string + service: + type: object + properties: + version: + type: string + environment: + type: string + message: + type: string + tags: + type: array + items: + type: string + responses: + '200': + description: Annotation created successfully + content: + application/json: + schema: + type: object + properties: + _id: + type: string + _index: + type: string + _source: + type: object + properties: + annotation: + type: string + tags: + type: array + items: + type: string + message: + type: string + service: + type: object + properties: + name: + type: string + environment: + type: string + version: + type: string + event: + type: object + properties: + created: + type: string + '@timestamp': + type: string + /s/{spaceId}/api/actions/connector: + post: + summary: Create a connector + operationId: createConnectorWithSpaceId + description: > + You must have `all` privileges for the **Actions and Connectors** + feature in the **Management** section of the Kibana feature privileges. + tags: + - connectors + parameters: + - $ref: '#/components/parameters/Connectors_kbn_xsrf' + - $ref: '#/components/parameters/Connectors_space_id' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Connectors_create_connector_request' + examples: + createEmailConnectorRequest: + $ref: >- + #/components/examples/Connectors_create_email_connector_request + createIndexConnectorRequest: + $ref: >- + #/components/examples/Connectors_create_index_connector_request + createWebhookConnectorRequest: + $ref: >- + #/components/examples/Connectors_create_webhook_connector_request + createXmattersConnectorRequest: + $ref: >- + #/components/examples/Connectors_create_xmatters_connector_request + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + $ref: '#/components/schemas/Connectors_connector_response_properties' + examples: + createEmailConnectorResponse: + $ref: >- + #/components/examples/Connectors_create_email_connector_response + createIndexConnectorResponse: + $ref: >- + #/components/examples/Connectors_create_index_connector_response + createWebhookConnectorResponse: + $ref: >- + #/components/examples/Connectors_create_webhook_connector_response + createXmattersConnectorResponse: + $ref: >- + #/components/examples/Connectors_create_xmatters_connector_response + '401': + $ref: '#/components/responses/Connectors_401' + security: + - Connectors_basicAuth: [] + - Connectors_apiKeyAuth: [] + /s/{spaceId}/api/actions/connector/{connectorId}: + get: + summary: Get connector information + operationId: getConnectorWithSpaceId + description: > + You must have `read` privileges for the **Actions and Connectors** + feature in the **Management** section of the Kibana feature privileges. + tags: + - connectors + parameters: + - $ref: '#/components/parameters/Connectors_connector_id' + - $ref: '#/components/parameters/Connectors_space_id' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + $ref: '#/components/schemas/Connectors_connector_response_properties' + examples: + getConnectorResponse: + $ref: '#/components/examples/Connectors_get_connector_response' + '401': + $ref: '#/components/responses/Connectors_401' + '404': + $ref: '#/components/responses/Connectors_404' + security: + - Connectors_basicAuth: [] + - Connectors_apiKeyAuth: [] + delete: + summary: Delete a connector + operationId: deleteConnectorWithSpaceId + description: > + You must have `all` privileges for the **Actions and Connectors** + feature in the **Management** section of the Kibana feature privileges. + WARNING: When you delete a connector, it cannot be recovered. + tags: + - connectors + parameters: + - $ref: '#/components/parameters/Connectors_kbn_xsrf' + - $ref: '#/components/parameters/Connectors_connector_id' + - $ref: '#/components/parameters/Connectors_space_id' + responses: + '204': + description: Indicates a successful call. + '401': + $ref: '#/components/responses/Connectors_401' + '404': + $ref: '#/components/responses/Connectors_404' + security: + - Connectors_basicAuth: [] + - Connectors_apiKeyAuth: [] + post: + summary: Create a connector + operationId: createConnectorIdWithSpaceId + description: > + You must have `all` privileges for the **Actions and Connectors** + feature in the **Management** section of the Kibana feature privileges. + tags: + - connectors + parameters: + - $ref: '#/components/parameters/Connectors_kbn_xsrf' + - $ref: '#/components/parameters/Connectors_space_id' + - in: path + name: connectorId + description: >- + A UUID v1 or v4 identifier for the connector. If you omit this + parameter, an identifier is randomly generated. + required: true + schema: + type: string + example: ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Connectors_create_connector_request' + examples: + createIndexConnectorRequest: + $ref: >- + #/components/examples/Connectors_create_index_connector_request + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + $ref: '#/components/schemas/Connectors_connector_response_properties' + examples: + createIndexConnectorResponse: + $ref: >- + #/components/examples/Connectors_create_index_connector_response + '401': + $ref: '#/components/responses/Connectors_401' + security: + - Connectors_basicAuth: [] + - Connectors_apiKeyAuth: [] + put: + summary: Update a connector + operationId: updateConnectorWithSpaceId + description: > + You must have `all` privileges for the **Actions and Connectors** + feature in the **Management** section of the Kibana feature privileges. + tags: + - connectors + parameters: + - $ref: '#/components/parameters/Connectors_kbn_xsrf' + - $ref: '#/components/parameters/Connectors_connector_id' + - $ref: '#/components/parameters/Connectors_space_id' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Connectors_update_connector_request' + examples: + updateIndexConnectorRequest: + $ref: >- + #/components/examples/Connectors_update_index_connector_request + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + $ref: '#/components/schemas/Connectors_connector_response_properties' + '400': + $ref: '#/components/responses/Connectors_401' + '401': + $ref: '#/components/responses/Connectors_401' + '404': + $ref: '#/components/responses/Connectors_404' + security: + - Connectors_basicAuth: [] + - Connectors_apiKeyAuth: [] + /s/{spaceId}/api/actions/connectors: + get: + summary: Get all connectors + operationId: getConnectorsWithSpaceId + description: > + You must have `read` privileges for the **Actions and Connectors** + feature in the **Management** section of the Kibana feature privileges. + tags: + - connectors + parameters: + - $ref: '#/components/parameters/Connectors_space_id' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: array + items: + $ref: >- + #/components/schemas/Connectors_connector_response_properties + examples: + getConnectorsResponse: + $ref: '#/components/examples/Connectors_get_connectors_response' + '401': + $ref: '#/components/responses/Connectors_401' + security: + - Connectors_basicAuth: [] + - Connectors_apiKeyAuth: [] + /s/{spaceId}/api/actions/connector_types: + get: + summary: Get all connector types + operationId: getConnectorTypesWithSpaceId + description: | + You do not need any Kibana feature privileges to run this API. + tags: + - connectors + parameters: + - $ref: '#/components/parameters/Connectors_space_id' + - in: query + name: feature_id + description: >- + A filter to limit the retrieved connector types to those that + support a specific feature (such as alerting or cases). + schema: + $ref: '#/components/schemas/Connectors_features' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + title: Get connector types response body properties + description: The properties vary for each connector type. + type: array + items: + type: object + properties: + enabled: + type: boolean + description: >- + Indicates whether the connector type is enabled in + Kibana. + example: true + enabled_in_config: + type: boolean + description: >- + Indicates whether the connector type is enabled in the + Kibana `.yml` file. + example: true + enabled_in_license: + type: boolean + description: >- + Indicates whether the connector is enabled in the + license. + example: true + id: + $ref: '#/components/schemas/Connectors_connector_types' + minimum_license_required: + type: string + description: The license that is required to use the connector type. + example: basic + name: + type: string + description: The name of the connector type. + example: Index + supported_feature_ids: + type: array + description: >- + The Kibana features that are supported by the connector + type. + items: + $ref: '#/components/schemas/Connectors_features' + example: + - alerting + - uptime + - siem + examples: + getConnectorTypesResponse: + $ref: >- + #/components/examples/Connectors_get_connector_types_response + '401': + $ref: '#/components/responses/Connectors_401' + security: + - Connectors_basicAuth: [] + - Connectors_apiKeyAuth: [] + /s/{spaceId}/api/actions/connector/{connectorId}/_execute: + post: + summary: Run a connector + operationId: runConnectorWithSpaceId + description: > + You can use this API to test an action that involves interaction with + Kibana services or integrations with third-party systems. You must have + `read` privileges for the **Actions and Connectors** feature in the + **Management** section of the Kibana feature privileges. If you use an + index connector, you must also have `all`, `create`, `index`, or `write` + indices privileges. + tags: + - connectors + parameters: + - $ref: '#/components/parameters/Connectors_kbn_xsrf' + - $ref: '#/components/parameters/Connectors_connector_id' + - $ref: '#/components/parameters/Connectors_space_id' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Connectors_run_connector_request' + examples: + runIndexConnectorRequest: + $ref: '#/components/examples/Connectors_run_index_connector_request' + runJiraConnectorRequest: + $ref: '#/components/examples/Connectors_run_jira_connector_request' + runServerLogConnectorRequest: + $ref: >- + #/components/examples/Connectors_run_server_log_connector_request + runServiceNowITOMConnectorRequest: + $ref: >- + #/components/examples/Connectors_run_servicenow_itom_connector_request + runSlackConnectorRequest: + $ref: >- + #/components/examples/Connectors_run_slack_api_connector_request + runSwimlaneConnectorRequest: + $ref: >- + #/components/examples/Connectors_run_swimlane_connector_request + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + required: + - connector_id + - status + properties: + connector_id: + type: string + description: The identifier for the connector. + data: + oneOf: + - type: object + description: Information returned from the action. + additionalProperties: true + - type: array + description: An array of information returned from the action. + items: + type: object + message: + type: string + service_message: + type: string + status: + type: string + description: The status of the action. + enum: + - error + - ok + examples: + runIndexConnectorResponse: + $ref: >- + #/components/examples/Connectors_run_index_connector_response + runJiraConnectorResponse: + $ref: '#/components/examples/Connectors_run_jira_connector_response' + runServerLogConnectorResponse: + $ref: >- + #/components/examples/Connectors_run_server_log_connector_response + runServiceNowITOMConnectorResponse: + $ref: >- + #/components/examples/Connectors_run_servicenow_itom_connector_response + runSlackConnectorResponse: + $ref: >- + #/components/examples/Connectors_run_slack_api_connector_response + runSwimlaneConnectorResponse: + $ref: >- + #/components/examples/Connectors_run_swimlane_connector_response + '401': + $ref: '#/components/responses/Connectors_401' + security: + - Connectors_basicAuth: [] + - Connectors_apiKeyAuth: [] + /api/actions/connector: + post: + summary: Create a connector + operationId: createConnector + tags: + - connectors + parameters: + - $ref: '#/components/parameters/Connectors_kbn_xsrf' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Connectors_create_connector_request' + examples: + createEmailConnectorRequest: + $ref: >- + #/components/examples/Connectors_create_email_connector_request + createIndexConnectorRequest: + $ref: >- + #/components/examples/Connectors_create_index_connector_request + createWebhookConnectorRequest: + $ref: >- + #/components/examples/Connectors_create_webhook_connector_request + createXmattersConnectorRequest: + $ref: >- + #/components/examples/Connectors_create_xmatters_connector_request + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + $ref: '#/components/schemas/Connectors_connector_response_properties' + examples: + createEmailConnectorResponse: + $ref: >- + #/components/examples/Connectors_create_email_connector_response + createIndexConnectorResponse: + $ref: >- + #/components/examples/Connectors_create_index_connector_response + createWebhookConnectorResponse: + $ref: >- + #/components/examples/Connectors_create_webhook_connector_response + createXmattersConnectorResponse: + $ref: >- + #/components/examples/Connectors_create_xmatters_connector_response + '401': + $ref: '#/components/responses/Connectors_401' + security: + - Connectors_basicAuth: [] + - Connectors_apiKeyAuth: [] + /api/actions/connector/{connectorId}: + get: + summary: Get a connector information + operationId: getConnector + tags: + - connectors + parameters: + - $ref: '#/components/parameters/Connectors_connector_id' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + $ref: '#/components/schemas/Connectors_connector_response_properties' + examples: + getConnectorResponse: + $ref: '#/components/examples/Connectors_get_connector_response' + '401': + $ref: '#/components/responses/Connectors_401' + '404': + $ref: '#/components/responses/Connectors_404' + security: + - Connectors_basicAuth: [] + - Connectors_apiKeyAuth: [] + delete: + summary: Delete a connector + operationId: deleteConnector + tags: + - connectors + parameters: + - $ref: '#/components/parameters/Connectors_kbn_xsrf' + - $ref: '#/components/parameters/Connectors_connector_id' + responses: + '204': + description: Indicates a successful call. + '401': + $ref: '#/components/responses/Connectors_401' + '404': + $ref: '#/components/responses/Connectors_404' + security: + - Connectors_basicAuth: [] + - Connectors_apiKeyAuth: [] + post: + summary: Create a connector + operationId: createConnectorId + tags: + - connectors + parameters: + - $ref: '#/components/parameters/Connectors_kbn_xsrf' + - in: path + name: connectorId + description: > + A UUID v1 or v4 identifier for the connector. If you omit this + parameter, an identifier is randomly generated. + required: true + schema: + type: string + example: ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Connectors_create_connector_request' + examples: + createIndexConnectorRequest: + $ref: >- + #/components/examples/Connectors_create_index_connector_request + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + $ref: '#/components/schemas/Connectors_connector_response_properties' + examples: + createIndexConnectorResponse: + $ref: >- + #/components/examples/Connectors_create_index_connector_response + '401': + $ref: '#/components/responses/Connectors_401' + security: + - Connectors_basicAuth: [] + - Connectors_apiKeyAuth: [] + put: + summary: Update a connector + operationId: updateConnector + tags: + - connectors + parameters: + - $ref: '#/components/parameters/Connectors_kbn_xsrf' + - $ref: '#/components/parameters/Connectors_connector_id' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Connectors_update_connector_request' + examples: + updateIndexConnectorRequest: + $ref: >- + #/components/examples/Connectors_update_index_connector_request + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + $ref: '#/components/schemas/Connectors_connector_response_properties' + '400': + $ref: '#/components/responses/Connectors_401' + '401': + $ref: '#/components/responses/Connectors_401' + '404': + $ref: '#/components/responses/Connectors_404' + security: + - Connectors_basicAuth: [] + - Connectors_apiKeyAuth: [] + /api/actions/connector/{connectorId}/_execute: + post: + summary: Run a connector + operationId: runConnector + description: > + You can use this API to test an action that involves interaction with + Kibana services or integrations with third-party systems. You must have + `read` privileges for the **Actions and Connectors** feature in the + **Management** section of the Kibana feature privileges. If you use an + index connector, you must also have `all`, `create`, `index`, or `write` + indices privileges. + tags: + - connectors + parameters: + - $ref: '#/components/parameters/Connectors_kbn_xsrf' + - $ref: '#/components/parameters/Connectors_connector_id' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Connectors_run_connector_request' + examples: + runCasesWebhookConnectorRequest: + $ref: >- + #/components/examples/Connectors_run_cases_webhook_connector_request + runEmailConnectorRequest: + $ref: '#/components/examples/Connectors_run_email_connector_request' + runIndexConnectorRequest: + $ref: '#/components/examples/Connectors_run_index_connector_request' + runJiraConnectorRequest: + $ref: '#/components/examples/Connectors_run_jira_connector_request' + runPagerDutyConnectorRequest: + $ref: >- + #/components/examples/Connectors_run_pagerduty_connector_request + runServerLogConnectorRequest: + $ref: >- + #/components/examples/Connectors_run_server_log_connector_request + runServiceNowITOMConnectorRequest: + $ref: >- + #/components/examples/Connectors_run_servicenow_itom_connector_request + runSlackConnectorRequest: + $ref: >- + #/components/examples/Connectors_run_slack_api_connector_request + runSwimlaneConnectorRequest: + $ref: >- + #/components/examples/Connectors_run_swimlane_connector_request + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + required: + - connector_id + - status + properties: + connector_id: + type: string + description: The identifier for the connector. + data: + oneOf: + - type: object + description: Information returned from the action. + additionalProperties: true + - type: array + description: An array of information returned from the action. + items: + type: object + status: + type: string + description: The status of the action. + enum: + - error + - ok + examples: + runCasesWebhookConnectorResponse: + $ref: >- + #/components/examples/Connectors_run_cases_webhook_connector_response + runEmailConnectorResponse: + $ref: >- + #/components/examples/Connectors_run_email_connector_response + runIndexConnectorResponse: + $ref: >- + #/components/examples/Connectors_run_index_connector_response + runJiraConnectorResponse: + $ref: '#/components/examples/Connectors_run_jira_connector_response' + runPagerDutyConnectorResponse: + $ref: >- + #/components/examples/Connectors_run_pagerduty_connector_response + runServerLogConnectorResponse: + $ref: >- + #/components/examples/Connectors_run_server_log_connector_response + runServiceNowITOMConnectorResponse: + $ref: >- + #/components/examples/Connectors_run_servicenow_itom_connector_response + runSlackConnectorResponse: + $ref: >- + #/components/examples/Connectors_run_slack_api_connector_response + runSwimlaneConnectorResponse: + $ref: >- + #/components/examples/Connectors_run_swimlane_connector_response + '401': + $ref: '#/components/responses/Connectors_401' + security: + - Connectors_basicAuth: [] + - Connectors_apiKeyAuth: [] + /api/actions/connectors: + get: + summary: Get all connectors + operationId: getConnectors + tags: + - connectors + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: array + items: + $ref: >- + #/components/schemas/Connectors_connector_response_properties + examples: + getConnectorsResponse: + $ref: '#/components/examples/Connectors_get_connectors_response' + '401': + $ref: '#/components/responses/Connectors_401' + security: + - Connectors_basicAuth: [] + - Connectors_apiKeyAuth: [] + /api/actions/connector_types: + get: + summary: Get all connector types + operationId: getConnectorTypes + tags: + - connectors + parameters: + - in: query + name: feature_id + description: >- + A filter to limit the retrieved connector types to those that + support a specific feature (such as alerting or cases). + schema: + $ref: '#/components/schemas/Connectors_features' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + title: Get connector types response body properties + description: The properties vary for each connector type. + type: array + items: + type: object + properties: + enabled: + type: boolean + description: >- + Indicates whether the connector type is enabled in + Kibana. + example: true + enabled_in_config: + type: boolean + description: >- + Indicates whether the connector type is enabled in the + Kibana configuration file. + example: true + enabled_in_license: + type: boolean + description: >- + Indicates whether the connector is enabled in the + license. + example: true + id: + $ref: '#/components/schemas/Connectors_connector_types' + is_system_action_type: + type: boolean + example: false + minimum_license_required: + type: string + description: The license that is required to use the connector type. + example: basic + name: + type: string + description: The name of the connector type. + example: Index + supported_feature_ids: + type: array + description: The features that are supported by the connector type. + items: + $ref: '#/components/schemas/Connectors_features' + example: + - alerting + - cases + - siem + examples: + getConnectorTypesServerlessResponse: + $ref: >- + #/components/examples/Connectors_get_connector_types_generativeai_response + '401': + $ref: '#/components/responses/Connectors_401' + security: + - Connectors_basicAuth: [] + - Connectors_apiKeyAuth: [] + /s/{spaceId}/api/actions/action/{actionId}: + delete: + summary: Delete a connector + operationId: legacyDeleteConnector + deprecated: true + description: > + Deprecated in 7.13.0. Use the delete connector API instead. WARNING: + When you delete a connector, it cannot be recovered. + tags: + - connectors + parameters: + - $ref: '#/components/parameters/Connectors_kbn_xsrf' + - $ref: '#/components/parameters/Connectors_action_id' + - $ref: '#/components/parameters/Connectors_space_id' + responses: + '204': + description: Indicates a successful call. + '401': + $ref: '#/components/responses/Connectors_401' + security: + - Connectors_basicAuth: [] + - Connectors_apiKeyAuth: [] + get: + summary: Get connector information + operationId: legacyGetConnector + description: Deprecated in 7.13.0. Use the get connector API instead. + deprecated: true + tags: + - connectors + parameters: + - $ref: '#/components/parameters/Connectors_action_id' + - $ref: '#/components/parameters/Connectors_space_id' + responses: + '200': + $ref: '#/components/responses/Connectors_200_actions' + '401': + $ref: '#/components/responses/Connectors_401' + security: + - Connectors_basicAuth: [] + - Connectors_apiKeyAuth: [] + put: + summary: Update a connector + operationId: legacyUpdateConnector + deprecated: true + description: Deprecated in 7.13.0. Use the update connector API instead. + tags: + - connectors + parameters: + - $ref: '#/components/parameters/Connectors_kbn_xsrf' + - $ref: '#/components/parameters/Connectors_action_id' + - $ref: '#/components/parameters/Connectors_space_id' + requestBody: + required: true + content: + application/json: + schema: + title: Legacy update connector request body properties + description: The properties vary depending on the connector type. + type: object + properties: + config: + type: object + description: >- + The new connector configuration. Configuration properties + vary depending on the connector type. + name: + type: string + description: The new name for the connector. + secrets: + type: object + description: >- + The updated secrets configuration for the connector. Secrets + properties vary depending on the connector type. + responses: + '200': + $ref: '#/components/responses/Connectors_200_actions' + '404': + $ref: '#/components/responses/Connectors_404' + security: + - Connectors_basicAuth: [] + - Connectors_apiKeyAuth: [] + /s/{spaceId}/api/actions: + get: + summary: Get all connectors + operationId: legacyGetConnectors + deprecated: true + description: Deprecated in 7.13.0. Use the get all connectors API instead. + tags: + - connectors + parameters: + - $ref: '#/components/parameters/Connectors_space_id' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Connectors_action_response_properties' + '401': + $ref: '#/components/responses/Connectors_401' + security: + - Connectors_basicAuth: [] + - Connectors_apiKeyAuth: [] + post: + summary: Create a connector + operationId: legacyCreateConnector + deprecated: true + description: Deprecated in 7.13.0. Use the create connector API instead. + tags: + - connectors + parameters: + - $ref: '#/components/parameters/Connectors_kbn_xsrf' + - $ref: '#/components/parameters/Connectors_space_id' + requestBody: + required: true + content: + application/json: + schema: + title: Legacy create connector request properties + type: object + properties: + actionTypeId: + type: string + description: The connector type identifier. + config: + type: object + description: >- + The configuration for the connector. Configuration + properties vary depending on the connector type. + name: + type: string + description: The display name for the connector. + secrets: + type: object + description: > + The secrets configuration for the connector. Secrets + configuration properties vary depending on the connector + type. NOTE: Remember these values. You must provide them + each time you update the connector. + responses: + '200': + $ref: '#/components/responses/Connectors_200_actions' + '401': + $ref: '#/components/responses/Connectors_401' + security: + - Connectors_basicAuth: [] + - Connectors_apiKeyAuth: [] + /s/{spaceId}/api/actions/list_action_types: + get: + summary: Get connector types + operationId: legacyGetConnectorTypes + deprecated: true + description: Deprecated in 7.13.0. Use the get all connector types API instead. + tags: + - connectors + parameters: + - $ref: '#/components/parameters/Connectors_space_id' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + title: Legacy get connector types response body properties + description: The properties vary for each connector type. + type: array + items: + type: object + properties: + enabled: + type: boolean + description: >- + Indicates whether the connector type is enabled in + Kibana. + enabledInConfig: + type: boolean + description: >- + Indicates whether the connector type is enabled in the + Kibana `.yml` file. + enabledInLicense: + type: boolean + description: >- + Indicates whether the connector is enabled in the + license. + example: true + id: + type: string + description: The unique identifier for the connector type. + minimumLicenseRequired: + type: string + description: The license that is required to use the connector type. + name: + type: string + description: The name of the connector type. + '401': + $ref: '#/components/responses/Connectors_401' + security: + - Connectors_basicAuth: [] + - Connectors_apiKeyAuth: [] + /s/{spaceId}/api/actions/action/{actionId}/_execute: + post: + summary: Run a connector + operationId: legacyRunConnector + deprecated: true + description: Deprecated in 7.13.0. Use the run connector API instead. + tags: + - connectors + parameters: + - $ref: '#/components/parameters/Connectors_kbn_xsrf' + - $ref: '#/components/parameters/Connectors_action_id' + - $ref: '#/components/parameters/Connectors_space_id' + requestBody: + required: true + content: + application/json: + schema: + title: Legacy run connector request body properties + description: The properties vary depending on the connector type. + type: object + required: + - params + properties: + params: + type: object + description: >- + The parameters of the connector. Parameter properties vary + depending on the connector type. + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + properties: + actionId: + type: string + data: + oneOf: + - type: object + description: Information returned from the action. + additionalProperties: true + - type: array + description: An array of information returned from the action. + items: + type: object + status: + type: string + description: The status of the action. + '401': + $ref: '#/components/responses/Connectors_401' + security: + - Connectors_basicAuth: [] + - Connectors_apiKeyAuth: [] + /s/{spaceId}/api/data_views: + get: + summary: Get all data views + operationId: getAllDataViews + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_space_id' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + properties: + data_view: + type: array + items: + type: object + properties: + id: + type: string + name: + type: string + namespaces: + type: array + items: + type: string + title: + type: string + typeMeta: + type: object + examples: + getAllDataViewsResponse: + $ref: '#/components/examples/Data_views_get_data_views_response' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + /s/{spaceId}/api/data_views/data_view: + post: + summary: Create a data view + operationId: createDataView + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_kbn_xsrf' + - $ref: '#/components/parameters/Data_views_space_id' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_create_data_view_request_object' + examples: + createDataViewRequest: + $ref: '#/components/examples/Data_views_create_data_view_request' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_data_view_response_object' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + /s/{spaceId}/api/data_views/data_view/{viewId}: + get: + summary: Get a data view + operationId: getDataView + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_view_id' + - $ref: '#/components/parameters/Data_views_space_id' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_data_view_response_object' + examples: + getDataViewResponse: + $ref: '#/components/examples/Data_views_get_data_view_response' + '404': + description: Object is not found. + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_404_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + delete: + summary: Delete a data view + operationId: deleteDataView + description: > + WARNING: When you delete a data view, it cannot be recovered. This + functionality is in technical preview and may be changed or removed in a + future release. Elastic will work to fix any issues, but features in + technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_kbn_xsrf' + - $ref: '#/components/parameters/Data_views_view_id' + - $ref: '#/components/parameters/Data_views_space_id' + responses: + '204': + description: Indicates a successful call. + '404': + description: Object is not found. + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_404_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + post: + summary: Update a data view + operationId: updateDataView + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_kbn_xsrf' + - $ref: '#/components/parameters/Data_views_view_id' + - $ref: '#/components/parameters/Data_views_space_id' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_update_data_view_request_object' + examples: + updateDataViewRequest: + $ref: '#/components/examples/Data_views_update_data_view_request' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_data_view_response_object' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + /s/{spaceId}/api/data_views/default: + get: + summary: Get the default data view identifier + operationId: getDefaultDataView + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_space_id' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + properties: + data_view_id: + type: string + examples: + getDefaultDataViewResponse: + $ref: >- + #/components/examples/Data_views_get_default_data_view_response + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + post: + summary: Sets the default data view identifier + operationId: setDefaultDatailView + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_kbn_xsrf' + - $ref: '#/components/parameters/Data_views_space_id' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - data_view_id + properties: + data_view_id: + type: string + nullable: true + description: > + The data view identifier. NOTE: The API does not validate + whether it is a valid identifier. Use `null` to unset the + default data view. + force: + type: boolean + description: Update an existing default data view identifier. + default: false + examples: + setDefaultDataViewRequest: + $ref: '#/components/examples/Data_views_set_default_data_view_request' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + properties: + acknowledged: + type: boolean + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + /s/{spaceId}/api/data_views/data_view/{viewId}/fields: + post: + summary: Update data view fields metadata + operationId: updateFieldsMetadata + description: > + Update fields presentation metadata such as count, customLabel and + format. 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. You can update multiple fields in one request. + Updates are merged with persisted metadata. To remove existing metadata, + specify null as the value. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_kbn_xsrf' + - $ref: '#/components/parameters/Data_views_view_id' + - $ref: '#/components/parameters/Data_views_space_id' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - fields + properties: + fields: + description: The field object. + type: object + examples: + updateFieldsMetadataRequest: + $ref: '#/components/examples/Data_views_update_field_metadata_request' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + properties: + acknowledged: + type: boolean + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + /s/{spaceId}/api/data_views/data_view/{viewId}/runtime_field: + post: + summary: Create a runtime field + operationId: createRuntimeField + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_kbn_xsrf' + - $ref: '#/components/parameters/Data_views_view_id' + - $ref: '#/components/parameters/Data_views_space_id' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - name + - runtimeField + properties: + name: + type: string + description: | + The name for a runtime field. + runtimeField: + type: object + description: | + The runtime field definition object. + examples: + createRuntimeFieldRequest: + $ref: '#/components/examples/Data_views_create_runtime_field_request' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + put: + summary: Create or update a runtime field + operationId: createUpdateRuntimeField + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_kbn_xsrf' + - $ref: '#/components/parameters/Data_views_space_id' + - name: viewId + in: path + description: | + The ID of the data view fields you want to update. + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - name + - runtimeField + properties: + name: + type: string + description: | + The name for a runtime field. + runtimeField: + type: object + description: | + The runtime field definition object. + examples: + updateRuntimeFieldRequest: + $ref: '#/components/examples/Data_views_create_runtime_field_request' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + properties: + data_view: + type: object + fields: + type: array + items: + type: object + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + /s/{spaceId}/api/data_views/data_view/{viewId}/runtime_field/{fieldName}: + get: + summary: Get a runtime field + operationId: getRuntimeField + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_field_name' + - $ref: '#/components/parameters/Data_views_view_id' + - $ref: '#/components/parameters/Data_views_space_id' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + properties: + data_view: + type: object + fields: + type: array + items: + type: object + examples: + getRuntimeFieldResponse: + $ref: '#/components/examples/Data_views_get_runtime_field_response' + '404': + description: Object is not found. + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_404_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + delete: + summary: Delete a runtime field from a data view + operationId: deleteRuntimeField + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_field_name' + - $ref: '#/components/parameters/Data_views_view_id' + - $ref: '#/components/parameters/Data_views_space_id' + responses: + '200': + description: Indicates a successful call. + '404': + description: Object is not found. + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_404_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + post: + summary: Update a runtime field + operationId: updateRuntimeField + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_field_name' + - $ref: '#/components/parameters/Data_views_view_id' + - $ref: '#/components/parameters/Data_views_space_id' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - runtimeField + properties: + runtimeField: + type: object + description: | + The runtime field definition object. + + You can update following fields: + + - `type` + - `script` + examples: + updateRuntimeFieldRequest: + $ref: '#/components/examples/Data_views_update_runtime_field_request' + responses: + '200': + description: Indicates a successful call. + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + /api/data_views: + get: + summary: Get all data views in the default space + operationId: getAllDataViewsDefault + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + properties: + data_view: + type: array + items: + type: object + properties: + id: + type: string + name: + type: string + namespaces: + type: array + items: + type: string + title: + type: string + typeMeta: + type: object + examples: + getAllDataViewsResponse: + $ref: '#/components/examples/Data_views_get_data_views_response' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + /api/data_views/data_view: + post: + summary: Create a data view in the default space + operationId: createDataViewDefault + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_kbn_xsrf' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_create_data_view_request_object' + examples: + createDataViewRequest: + $ref: '#/components/examples/Data_views_create_data_view_request' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_data_view_response_object' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + /api/data_views/data_view/{viewId}: + get: + summary: Get a data view in the default space + operationId: getDataViewDefault + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_view_id' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_data_view_response_object' + examples: + getDataViewResponse: + $ref: '#/components/examples/Data_views_get_data_view_response' + '404': + description: Object is not found. + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_404_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + delete: + summary: Delete a data view from the default space + operationId: deleteDataViewDefault + description: > + WARNING: When you delete a data view, it cannot be recovered. This + functionality is in technical preview and may be changed or removed in a + future release. Elastic will work to fix any issues, but features in + technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_kbn_xsrf' + - $ref: '#/components/parameters/Data_views_view_id' + responses: + '204': + description: Indicates a successful call. + '404': + description: Object is not found. + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_404_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + post: + summary: Update a data view in the default space + operationId: updateDataViewDefault + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_kbn_xsrf' + - $ref: '#/components/parameters/Data_views_view_id' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_update_data_view_request_object' + examples: + updateDataViewRequest: + $ref: '#/components/examples/Data_views_update_data_view_request' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_data_view_response_object' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + /api/data_views/data_view/{viewId}/fields: + post: + summary: Update data view fields metadata in the default space + operationId: updateFieldsMetadataDefault + description: > + Update fields presentation metadata such as count, customLabel, + customDescription, and format. 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. You can update + multiple fields in one request. Updates are merged with persisted + metadata. To remove existing metadata, specify null as the value. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_kbn_xsrf' + - $ref: '#/components/parameters/Data_views_view_id' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - fields + properties: + fields: + description: The field object. + type: object + examples: + updateFieldsMetadataRequest: + $ref: '#/components/examples/Data_views_update_field_metadata_request' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + properties: + acknowledged: + type: boolean + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + /api/data_views/data_view/{viewId}/runtime_field: + post: + summary: Create a runtime field in the default space + operationId: createRuntimeFieldDefault + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_kbn_xsrf' + - $ref: '#/components/parameters/Data_views_view_id' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - name + - runtimeField + properties: + name: + type: string + description: | + The name for a runtime field. + runtimeField: + type: object + description: | + The runtime field definition object. + examples: + createRuntimeFieldRequest: + $ref: '#/components/examples/Data_views_create_runtime_field_request' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + put: + summary: Create or update a runtime field in the default space + operationId: createUpdateRuntimeFieldDefault + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_kbn_xsrf' + - name: viewId + in: path + description: | + The ID of the data view fields you want to update. + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - name + - runtimeField + properties: + name: + type: string + description: | + The name for a runtime field. + runtimeField: + type: object + description: | + The runtime field definition object. + examples: + updateRuntimeFieldRequest: + $ref: '#/components/examples/Data_views_create_runtime_field_request' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + properties: + data_view: + type: object + fields: + type: array + items: + type: object + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + /api/data_views/data_view/{viewId}/runtime_field/{fieldName}: + get: + summary: Get a runtime field in the default space + operationId: getRuntimeFieldDefault + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_field_name' + - $ref: '#/components/parameters/Data_views_view_id' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + properties: + data_view: + type: object + fields: + type: array + items: + type: object + examples: + getRuntimeFieldResponse: + $ref: '#/components/examples/Data_views_get_runtime_field_response' + '404': + description: Object is not found. + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_404_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + delete: + summary: Delete a runtime field from a data view in the default space + operationId: deleteRuntimeFieldDefault + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_field_name' + - $ref: '#/components/parameters/Data_views_view_id' + responses: + '200': + description: Indicates a successful call. + '404': + description: Object is not found. + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_404_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + post: + summary: Update a runtime field in the default space + operationId: updateRuntimeFieldDefault + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_field_name' + - $ref: '#/components/parameters/Data_views_view_id' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - runtimeField + properties: + runtimeField: + type: object + description: | + The runtime field definition object. + + You can update following fields: + + - `type` + - `script` + examples: + updateRuntimeFieldRequest: + $ref: '#/components/examples/Data_views_update_runtime_field_request' + responses: + '200': + description: Indicates a successful call. + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + /api/data_views/default: + get: + summary: Get the default data view in the default space + operationId: getDefaultDataViewDefault + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + properties: + data_view_id: + type: string + examples: + getDefaultDataViewResponse: + $ref: >- + #/components/examples/Data_views_get_default_data_view_response + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + post: + summary: Set the default data view in the default space + operationId: setDefaultDatailViewDefault + description: > + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - data views + parameters: + - $ref: '#/components/parameters/Data_views_kbn_xsrf' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - data_view_id + properties: + data_view_id: + type: string + nullable: true + description: > + The data view identifier. NOTE: The API does not validate + whether it is a valid identifier. Use `null` to unset the + default data view. + force: + type: boolean + description: Update an existing default data view identifier. + default: false + examples: + setDefaultDataViewRequest: + $ref: '#/components/examples/Data_views_set_default_data_view_request' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + properties: + acknowledged: + type: boolean + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Data_views_400_response' + security: + - Data_views_basicAuth: [] + - Data_views_apiKeyAuth: [] + /api/ml/saved_objects/sync: + get: + summary: Sync saved objects in the default space + description: > + Synchronizes Kibana saved objects for machine learning jobs and trained + models in the default space. You must have `all` privileges for the + **Machine Learning** feature in the **Analytics** section of the Kibana + feature privileges. This API runs automatically when you start Kibana + and periodically thereafter. + operationId: mlSync + tags: + - ml + parameters: + - $ref: '#/components/parameters/Machine_learning_APIs_simulateParam' + responses: + '200': + description: Indicates a successful call + content: + application/json: + schema: + $ref: '#/components/schemas/Machine_learning_APIs_mlSync200Response' + examples: + syncExample: + $ref: '#/components/examples/Machine_learning_APIs_mlSyncExample' + '401': + description: Authorization information is missing or invalid. + content: + application/json: + schema: + $ref: '#/components/schemas/Machine_learning_APIs_mlSync4xxResponse' + security: + - Machine_learning_APIs_basicAuth: [] + - Machine_learning_APIs_apiKeyAuth: [] + /s/{spaceId}/api/ml/saved_objects/sync: + get: + summary: Sync saved objects + description: > + Synchronizes Kibana saved objects for machine learning jobs and trained + models. You must have `all` privileges for the **Machine Learning** + feature in the **Analytics** section of the Kibana feature privileges. + This API runs automatically when you start Kibana and periodically + thereafter. + operationId: mlSyncWithSpaceId + tags: + - ml + parameters: + - $ref: '#/components/parameters/Machine_learning_APIs_spaceParam' + - $ref: '#/components/parameters/Machine_learning_APIs_simulateParam' + responses: + '200': + description: Indicates a successful call + content: + application/json: + schema: + $ref: '#/components/schemas/Machine_learning_APIs_mlSync200Response' + examples: + syncExample: + $ref: '#/components/examples/Machine_learning_APIs_mlSyncExample' + '401': + description: Authorization information is missing or invalid. + content: + application/json: + schema: + $ref: '#/components/schemas/Machine_learning_APIs_mlSync4xxResponse' + security: + - Machine_learning_APIs_basicAuth: [] + - Machine_learning_APIs_apiKeyAuth: [] + /api/encrypted_saved_objects/_rotate_key: + post: + summary: Rotate a key for encrypted saved objects + operationId: rotateEncryptionKey + description: > + Superuser role required. + + + If a saved object cannot be decrypted using the primary encryption key, + then Kibana will attempt to decrypt it using the specified + decryption-only keys. In most of the cases this overhead is negligible, + but if you're dealing with a large number of saved objects and + experiencing performance issues, you may want to rotate the encryption + key. + + + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - saved objects + parameters: + - in: query + name: batch_size + schema: + type: number + default: 10000 + required: false + description: > + Specifies a maximum number of saved objects that Kibana can process + in a single batch. Bulk key rotation is an iterative process since + Kibana may not be able to fetch and process all required saved + objects in one go and splits processing into consequent batches. By + default, the batch size is 10000, which is also a maximum allowed + value. + - in: query + name: type + schema: + type: string + required: false + description: > + Limits encryption key rotation only to the saved objects with the + specified type. By default, Kibana tries to rotate the encryption + key for all saved object types that may contain encrypted + attributes. + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + properties: + total: + type: number + description: > + Indicates the total number of all encrypted saved objects + (optionally filtered by the requested `type`), regardless + of the key Kibana used for encryption. + successful: + type: number + description: > + Indicates the total number of all encrypted saved objects + (optionally filtered by the requested `type`), regardless + of the key Kibana used for encryption. + + + NOTE: In most cases, `total` will be greater than + `successful` even if `failed` is zero. The reason is that + Kibana may not need or may not be able to rotate + encryption keys for all encrypted saved objects. + failed: + type: number + description: > + Indicates the number of the saved objects that were still + encrypted with one of the old encryption keys that Kibana + failed to re-encrypt with the primary key. + examples: + rotateEncryptionKeyResponse: + $ref: '#/components/examples/Saved_objects_key_rotation_response' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Saved_objects_400_response' + '429': + description: Already in progress. + content: + application/json: + schema: + type: object + security: + - Saved_objects_basicAuth: [] + - Saved_objects_apiKeyAuth: [] + /api/saved_objects/_bulk_create: + post: + summary: Create saved objects + operationId: bulkCreateSavedObjects + deprecated: true + tags: + - saved objects + parameters: + - $ref: '#/components/parameters/Saved_objects_kbn_xsrf' + - in: query + name: overwrite + description: When true, overwrites the document with the same identifier. + schema: + type: boolean + requestBody: + required: true + content: + application/json: + schema: + type: array + items: + type: object + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Saved_objects_400_response' + security: + - Saved_objects_basicAuth: [] + - Saved_objects_apiKeyAuth: [] + /api/saved_objects/_bulk_delete: + post: + summary: Delete saved objects + operationId: bulkDeleteSavedObjects + description: | + WARNING: When you delete a saved object, it cannot be recovered. + deprecated: true + tags: + - saved objects + parameters: + - $ref: '#/components/parameters/Saved_objects_kbn_xsrf' + - in: query + name: force + description: > + When true, force delete objects that exist in multiple namespaces. + Note that the option applies to the whole request. Use the delete + object API to specify per-object deletion behavior. TIP: Use this if + you attempted to delete objects and received an HTTP 400 error with + the following message: "Unable to delete saved object that exists in + multiple namespaces, use the force option to delete it anyway". + WARNING: When you bulk delete objects that exist in multiple + namespaces, the API also deletes legacy url aliases that reference + the object. These requests are batched to minimise the impact but + they can place a heavy load on Kibana. Make sure you limit the + number of objects that exist in multiple namespaces in a single bulk + delete operation. + schema: + type: boolean + requestBody: + required: true + content: + application/json: + schema: + type: array + items: + type: object + 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. + content: + application/json: + schema: + type: object + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Saved_objects_400_response' + security: + - Saved_objects_basicAuth: [] + - Saved_objects_apiKeyAuth: [] + /api/saved_objects/_bulk_get: + post: + summary: Get saved objects + operationId: bulkGetSavedObjects + deprecated: true + tags: + - saved objects + parameters: + - $ref: '#/components/parameters/Saved_objects_kbn_xsrf' + requestBody: + required: true + content: + application/json: + schema: + type: array + items: + type: object + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Saved_objects_400_response' + security: + - Saved_objects_basicAuth: [] + - Saved_objects_apiKeyAuth: [] + /api/saved_objects/_bulk_resolve: + post: + summary: Resolve saved objects + operationId: bulkResolveSavedObjects + deprecated: true + description: > + Retrieve multiple Kibana saved objects by identifier 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 by the bulk resolve API + using either its new ID or its old ID. + tags: + - saved objects + parameters: + - $ref: '#/components/parameters/Saved_objects_kbn_xsrf' + requestBody: + required: true + content: + application/json: + schema: + type: array + items: + type: object + 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. + content: + application/json: + schema: + type: object + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Saved_objects_400_response' + security: + - Saved_objects_basicAuth: [] + - Saved_objects_apiKeyAuth: [] + /api/saved_objects/_bulk_update: + post: + summary: Update saved objects + operationId: bulkUpdateSavedObjects + description: Update the attributes for multiple Kibana saved objects. + deprecated: true + tags: + - saved objects + parameters: + - $ref: '#/components/parameters/Saved_objects_kbn_xsrf' + requestBody: + required: true + content: + application/json: + schema: + type: array + items: + type: object + 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. + content: + application/json: + schema: + type: object + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Saved_objects_400_response' + security: + - Saved_objects_basicAuth: [] + - Saved_objects_apiKeyAuth: [] + /api/saved_objects/_export: + post: + summary: Export saved objects in the default space + operationId: exportSavedObjectsDefault + description: > + Retrieve sets of saved objects that you want to import into Kibana. + + You must include `type` or `objects` in the request body. + + + NOTE: The `savedObjects.maxImportExportSize` configuration setting + limits the number of saved objects which may be exported. + + + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - saved objects + parameters: + - $ref: '#/components/parameters/Saved_objects_kbn_xsrf' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + excludeExportDetails: + description: Do not add export details entry at the end of the stream. + type: boolean + default: false + includeReferencesDeep: + description: >- + Includes all of the referenced objects in the exported + objects. + type: boolean + objects: + description: A list of objects to export. + type: array + items: + type: object + type: + description: >- + The saved object types to include in the export. Use `*` to + export all the types. + oneOf: + - type: string + - type: array + items: + type: string + examples: + exportSavedObjectsRequest: + $ref: '#/components/examples/Saved_objects_export_objects_request' + responses: + '200': + description: Indicates a successful call. + content: + application/x-ndjson: + schema: + type: object + additionalProperties: true + examples: + exportSavedObjectsResponse: + $ref: '#/components/examples/Saved_objects_export_objects_response' + '400': + description: Bad request. + content: + application/json: + schema: + $ref: '#/components/schemas/Saved_objects_400_response' + security: + - Saved_objects_basicAuth: [] + - Saved_objects_apiKeyAuth: [] + /api/saved_objects/_find: + get: + summary: Search for saved objects + operationId: findSavedObjects + description: Retrieve a paginated set of Kibana saved objects. + deprecated: true + tags: + - saved objects + parameters: + - in: query + name: aggs + description: > + An aggregation structure, serialized as a string. The field format + is similar to filter, meaning that to use a saved object type + attribute in the aggregation, the `savedObjectType.attributes.title: + "myTitle"` format must be used. For root fields, the syntax is + `savedObjectType.rootField`. NOTE: As objects change in Kibana, the + results on each page of the response also change. Use the find API + for traditional paginated results, but avoid using it to export + large amounts of data. + schema: + type: string + - in: query + name: default_search_operator + description: The default operator to use for the `simple_query_string`. + schema: + type: string + - in: query + name: fields + description: The fields to return in the attributes key of the response. + schema: + oneOf: + - type: string + - type: array + - in: query + name: filter + description: > + The filter is a KQL string with the caveat that if you filter with + an attribute from your saved object type, it should look like that: + `savedObjectType.attributes.title: "myTitle"`. However, if you use a + root attribute of a saved object such as `updated_at`, you will have + to define your filter like that: `savedObjectType.updated_at > + 2018-12-22`. + schema: + type: string + - in: query + name: has_no_reference + description: >- + Filters to objects that do not have a relationship with the type and + identifier combination. + schema: + type: object + - in: query + name: has_no_reference_operator + description: >- + The operator to use for the `has_no_reference` parameter. Either + `OR` or `AND`. Defaults to `OR`. + schema: + type: string + - in: query + name: has_reference + description: >- + Filters to objects that have a relationship with the type and ID + combination. + schema: + type: object + - in: query + name: has_reference_operator + description: >- + The operator to use for the `has_reference` parameter. Either `OR` + or `AND`. Defaults to `OR`. + schema: + type: string + - in: query + name: page + description: The page of objects to return. + schema: + type: integer + - in: query + name: per_page + description: The number of objects to return per page. + schema: + type: integer + - in: query + name: search + description: >- + An Elasticsearch `simple_query_string` query that filters the + objects in the response. + schema: + type: string + - in: query + name: search_fields + description: >- + The fields to perform the `simple_query_string` parsed query + against. + schema: + oneOf: + - type: string + - type: array + - in: query + name: sort_field + description: > + Sorts the response. Includes "root" and "type" fields. "root" fields + exist for all saved objects, such as "updated_at". "type" fields are + specific to an object type, such as fields returned in the + attributes key of the response. When a single type is defined in the + type parameter, the "root" and "type" fields are allowed, and + validity checks are made in that order. When multiple types are + defined in the type parameter, only "root" fields are allowed. + schema: + type: string + - in: query + name: type + description: The saved object types to include. + required: true + schema: + oneOf: + - type: string + - type: array + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Saved_objects_400_response' + security: + - Saved_objects_basicAuth: [] + - Saved_objects_apiKeyAuth: [] + /api/saved_objects/_import: + post: + summary: Import saved objects in the default space + operationId: importSavedObjectsDefault + description: > + Create sets of Kibana saved objects from a file created by the export + API. + + Saved objects can be imported only into the same version, a newer minor + on the same major, or the next major. Exported saved objects are not + backwards compatible and cannot be imported into an older version of + Kibana. + + + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - saved objects + parameters: + - $ref: '#/components/parameters/Saved_objects_kbn_xsrf' + - in: query + name: createNewCopies + schema: + type: boolean + required: false + description: > + Creates copies of saved objects, regenerates each object ID, and + resets the origin. When used, potential conflict errors are avoided. + NOTE: This option cannot be used with the `overwrite` and + `compatibilityMode` options. + - in: query + name: overwrite + schema: + type: boolean + required: false + description: > + Overwrites saved objects when they already exist. When used, + potential conflict errors are automatically resolved by overwriting + the destination object. NOTE: This option cannot be used with the + `createNewCopies` option. + - in: query + name: compatibilityMode + schema: + type: boolean + required: false + description: > + Applies various adjustments to the saved objects that are being + imported to maintain compatibility between different Kibana + versions. Use this option only if you encounter issues with imported + saved objects. NOTE: This option cannot be used with the + `createNewCopies` option. + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + file: + description: > + A file exported using the export API. NOTE: The + `savedObjects.maxImportExportSize` configuration setting + limits the number of saved objects which may be included in + this file. Similarly, the + `savedObjects.maxImportPayloadBytes` setting limits the + overall size of the file that can be imported. + examples: + importObjectsRequest: + $ref: '#/components/examples/Saved_objects_import_objects_request' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + description: > + Indicates when the import was successfully completed. When + set to false, some objects may not have been created. For + additional information, refer to the `errors` and + `successResults` properties. + successCount: + type: integer + description: Indicates the number of successfully imported records. + errors: + type: array + items: + type: object + description: > + Indicates the import was unsuccessful and specifies the + objects that failed to import. + + + NOTE: One object may result in multiple errors, which + requires separate steps to resolve. For instance, a + `missing_references` error and conflict error. + successResults: + type: array + items: + type: object + description: > + Indicates the objects that are successfully imported, with + any metadata if applicable. + + + NOTE: Objects are created only when all resolvable errors + are addressed, including conflicts and missing references. + If objects are created as new copies, each entry in the + `successResults` array includes a `destinationId` + attribute. + examples: + importObjectsResponse: + $ref: '#/components/examples/Saved_objects_import_objects_response' + '400': + description: Bad request. + content: + application/json: + schema: + $ref: '#/components/schemas/Saved_objects_400_response' + security: + - Saved_objects_basicAuth: [] + - Saved_objects_apiKeyAuth: [] + /api/saved_objects/_resolve_import_errors: + post: + summary: Resolve import errors + operationId: resolveImportErrors + description: > + To resolve errors from the Import objects API, you can: + + + * Retry certain saved objects + + * Overwrite specific saved objects + + * Change references to different saved objects + + + This functionality is in technical preview and may be changed or removed + in a future release. Elastic will work to fix any issues, but features + in technical preview are not subject to the support SLA of official GA + features. + tags: + - saved objects + parameters: + - $ref: '#/components/parameters/Saved_objects_kbn_xsrf' + - in: query + name: compatibilityMode + schema: + type: boolean + required: false + description: > + Applies various adjustments to the saved objects that are being + imported to maintain compatibility between different Kibana + versions. When enabled during the initial import, also enable when + resolving import errors. This option cannot be used with the + `createNewCopies` option. + - in: query + name: createNewCopies + schema: + type: boolean + required: false + description: > + Creates copies of the saved objects, regenerates each object ID, and + resets the origin. When enabled during the initial import, also + enable when resolving import errors. + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + required: + - retries + properties: + file: + description: The same file given to the import API. + type: string + format: binary + retries: + description: >- + The retry operations, which can specify how to resolve + different types of errors. + type: array + items: + type: object + required: + - type + - id + properties: + type: + description: The saved object type. + type: string + id: + description: The saved object ID. + type: string + overwrite: + description: >- + When set to `true`, the source object overwrites the + conflicting destination object. When set to `false`, + does nothing. + type: boolean + destinationId: + description: >- + Specifies the destination ID that the imported object + should have, if different from the current ID. + type: string + replaceReferences: + description: >- + A list of `type`, `from`, and `to` used to change the + object references. + type: array + items: + type: object + properties: + type: + type: string + from: + type: string + to: + type: string + ignoreMissingReferences: + description: >- + When set to `true`, ignores missing reference errors. + When set to `false`, does nothing. + type: boolean + examples: + resolveImportErrorsRequest: + $ref: >- + #/components/examples/Saved_objects_resolve_missing_reference_request + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + description: > + Indicates a successful import. When set to `false`, some + objects may not have been created. For additional + information, refer to the `errors` and `successResults` + properties. + successCount: + type: number + description: | + Indicates the number of successfully resolved records. + errors: + type: array + description: > + Specifies the objects that failed to resolve. + + + NOTE: One object can result in multiple errors, which + requires separate steps to resolve. For instance, a + `missing_references` error and a `conflict` error. + items: + type: object + successResults: + type: array + description: > + Indicates the objects that are successfully imported, with + any metadata if applicable. + + + NOTE: Objects are only created when all resolvable errors + are addressed, including conflict and missing references. + items: + type: object + examples: + resolveImportErrorsResponse: + $ref: >- + #/components/examples/Saved_objects_resolve_missing_reference_response + '400': + description: Bad request. + content: + application/json: + schema: + $ref: '#/components/schemas/Saved_objects_400_response' + security: + - Saved_objects_basicAuth: [] + - Saved_objects_apiKeyAuth: [] + /api/saved_objects/{type}: + post: + summary: Create a saved object + operationId: createSavedObject + description: Create a Kibana saved object with a randomly generated identifier. + deprecated: true + tags: + - saved objects + parameters: + - $ref: '#/components/parameters/Saved_objects_kbn_xsrf' + - $ref: '#/components/parameters/Saved_objects_saved_object_type' + - in: query + name: overwrite + description: If true, overwrites the document with the same identifier. + schema: + type: boolean + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - attributes + properties: + attributes: + $ref: '#/components/schemas/Saved_objects_attributes' + initialNamespaces: + $ref: '#/components/schemas/Saved_objects_initial_namespaces' + references: + $ref: '#/components/schemas/Saved_objects_references' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + '409': + description: Indicates a conflict error. + content: + application/json: + schema: + type: object + security: + - Saved_objects_basicAuth: [] + - Saved_objects_apiKeyAuth: [] + /api/saved_objects/{type}/{id}: + get: + summary: Get a saved object + operationId: getSavedObject + description: Retrieve a single Kibana saved object by identifier. + deprecated: true + tags: + - saved objects + parameters: + - $ref: '#/components/parameters/Saved_objects_saved_object_id' + - $ref: '#/components/parameters/Saved_objects_saved_object_type' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + '400': + description: Bad request. + content: + application/json: + schema: + $ref: '#/components/schemas/Saved_objects_400_response' + security: + - Saved_objects_basicAuth: [] + - Saved_objects_apiKeyAuth: [] + post: + summary: Create a saved object + operationId: createSavedObjectId + description: >- + Create a Kibana saved object and specify its identifier instead of using + a randomly generated ID. + deprecated: true + tags: + - saved objects + parameters: + - $ref: '#/components/parameters/Saved_objects_kbn_xsrf' + - $ref: '#/components/parameters/Saved_objects_saved_object_id' + - $ref: '#/components/parameters/Saved_objects_saved_object_type' + - in: query + name: overwrite + description: If true, overwrites the document with the same identifier. + schema: + type: boolean + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - attributes + properties: + attributes: + $ref: '#/components/schemas/Saved_objects_attributes' + initialNamespaces: + $ref: '#/components/schemas/Saved_objects_initial_namespaces' + references: + $ref: '#/components/schemas/Saved_objects_initial_namespaces' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + '409': + description: Indicates a conflict error. + content: + application/json: + schema: + type: object + security: + - Saved_objects_basicAuth: [] + - Saved_objects_apiKeyAuth: [] + put: + summary: Update a saved object + operationId: updateSavedObject + description: Update the attributes for Kibana saved objects. + deprecated: true + tags: + - saved objects + parameters: + - $ref: '#/components/parameters/Saved_objects_kbn_xsrf' + - $ref: '#/components/parameters/Saved_objects_saved_object_id' + - $ref: '#/components/parameters/Saved_objects_saved_object_type' + requestBody: + required: true + content: + application/json: + schema: + type: object + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + '404': + description: Indicates the object was not found. + content: + application/json: + schema: + type: object + '409': + description: Indicates a conflict error. + content: + application/json: + schema: + type: object + security: + - Saved_objects_basicAuth: [] + - Saved_objects_apiKeyAuth: [] + /api/saved_objects/resolve/{type}/{id}: + get: + summary: Resolve a saved object + operationId: resolveSavedObject + description: > + Retrieve a single Kibana saved object by identifier 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 using either its new ID or + its old ID. + deprecated: true + tags: + - saved objects + parameters: + - $ref: '#/components/parameters/Saved_objects_saved_object_id' + - $ref: '#/components/parameters/Saved_objects_saved_object_type' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + type: object + '400': + description: Bad request. + content: + application/json: + schema: + $ref: '#/components/schemas/Saved_objects_400_response' + security: + - Saved_objects_basicAuth: [] + - Saved_objects_apiKeyAuth: [] + /s/{spaceId}/api/observability/slos: + post: + summary: Create an SLO + operationId: createSloOp + description: > + You must have `all` privileges for the **SLOs** feature in the + **Observability** section of the Kibana feature privileges. + tags: + - slo + parameters: + - $ref: '#/components/parameters/SLOs_kbn_xsrf' + - $ref: '#/components/parameters/SLOs_space_id' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_create_slo_request' + responses: + '200': + description: Successful request + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_create_slo_response' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_400_response' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_401_response' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_403_response' + '409': + description: Conflict - The SLO id already exists + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_409_response' + servers: + - url: https://localhost:5601 + security: + - SLOs_basicAuth: [] + - SLOs_apiKeyAuth: [] + get: + summary: Get a paginated list of SLOs + operationId: findSlosOp + description: > + You must have the `read` privileges for the **SLOs** feature in the + **Observability** section of the Kibana feature privileges. + tags: + - slo + parameters: + - $ref: '#/components/parameters/SLOs_kbn_xsrf' + - $ref: '#/components/parameters/SLOs_space_id' + - name: kqlQuery + in: query + description: A valid kql query to filter the SLO with + schema: + type: string + example: 'slo.name:latency* and slo.tags : "prod"' + - name: page + in: query + description: The page to use for pagination, must be greater or equal than 1 + schema: + type: integer + default: 1 + example: 1 + - name: perPage + in: query + description: Number of SLOs returned by page + schema: + type: integer + default: 25 + maximum: 5000 + example: 25 + - name: sortBy + in: query + description: Sort by field + schema: + type: string + enum: + - sli_value + - status + - error_budget_consumed + - error_budget_remaining + default: status + example: status + - name: sortDirection + in: query + description: Sort order + schema: + type: string + enum: + - asc + - desc + default: asc + example: asc + - name: hideStale + in: query + description: >- + Hide stale SLOs from the list as defined by stale SLO threshold in + SLO settings + schema: + type: boolean + responses: + '200': + description: Successful request + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_find_slo_response' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_400_response' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_401_response' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_403_response' + '404': + description: Not found response + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_404_response' + security: + - SLOs_basicAuth: [] + - SLOs_apiKeyAuth: [] + /s/{spaceId}/api/observability/slos/{sloId}: + get: + summary: Get an SLO + operationId: getSloOp + description: > + You must have the `read` privileges for the **SLOs** feature in the + **Observability** section of the Kibana feature privileges. + tags: + - slo + parameters: + - $ref: '#/components/parameters/SLOs_kbn_xsrf' + - $ref: '#/components/parameters/SLOs_space_id' + - $ref: '#/components/parameters/SLOs_slo_id' + - name: instanceId + in: query + description: the specific instanceId used by the summary calculation + schema: + type: string + example: host-abcde + responses: + '200': + description: Successful request + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_slo_with_summary_response' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_400_response' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_401_response' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_403_response' + '404': + description: Not found response + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_404_response' + security: + - SLOs_basicAuth: [] + - SLOs_apiKeyAuth: [] + put: + summary: Update an SLO + operationId: updateSloOp + description: > + You must have the `write` privileges for the **SLOs** feature in the + **Observability** section of the Kibana feature privileges. + tags: + - slo + parameters: + - $ref: '#/components/parameters/SLOs_kbn_xsrf' + - $ref: '#/components/parameters/SLOs_space_id' + - $ref: '#/components/parameters/SLOs_slo_id' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_update_slo_request' + responses: + '200': + description: Successful request + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_slo_definition_response' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_400_response' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_401_response' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_403_response' + '404': + description: Not found response + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_404_response' + security: + - SLOs_basicAuth: [] + - SLOs_apiKeyAuth: [] + delete: + summary: Delete an SLO + operationId: deleteSloOp + description: > + You must have the `write` privileges for the **SLOs** feature in the + **Observability** section of the Kibana feature privileges. + tags: + - slo + parameters: + - $ref: '#/components/parameters/SLOs_kbn_xsrf' + - $ref: '#/components/parameters/SLOs_space_id' + - $ref: '#/components/parameters/SLOs_slo_id' + responses: + '204': + description: Successful request + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_400_response' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_401_response' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_403_response' + '404': + description: Not found response + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_404_response' + security: + - SLOs_basicAuth: [] + - SLOs_apiKeyAuth: [] + /s/{spaceId}/api/observability/slos/{sloId}/enable: + post: + summary: Enable an SLO + operationId: enableSloOp + description: > + You must have the `write` privileges for the **SLOs** feature in the + **Observability** section of the Kibana feature privileges. + tags: + - slo + parameters: + - $ref: '#/components/parameters/SLOs_kbn_xsrf' + - $ref: '#/components/parameters/SLOs_space_id' + - $ref: '#/components/parameters/SLOs_slo_id' + responses: + '204': + description: Successful request + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_400_response' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_401_response' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_403_response' + '404': + description: Not found response + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_404_response' + security: + - SLOs_basicAuth: [] + - SLOs_apiKeyAuth: [] + /s/{spaceId}/api/observability/slos/{sloId}/disable: + post: + summary: Disable an SLO + operationId: disableSloOp + description: > + You must have the `write` privileges for the **SLOs** feature in the + **Observability** section of the Kibana feature privileges. + tags: + - slo + parameters: + - $ref: '#/components/parameters/SLOs_kbn_xsrf' + - $ref: '#/components/parameters/SLOs_space_id' + - $ref: '#/components/parameters/SLOs_slo_id' + responses: + '200': + description: Successful request + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_400_response' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_401_response' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_403_response' + '404': + description: Not found response + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_404_response' + security: + - SLOs_basicAuth: [] + - SLOs_apiKeyAuth: [] + /s/{spaceId}/api/observability/slos/{sloId}/_reset: + post: + summary: Reset an SLO + operationId: resetSloOp + description: > + You must have the `write` privileges for the **SLOs** feature in the + **Observability** section of the Kibana feature privileges. + tags: + - slo + parameters: + - $ref: '#/components/parameters/SLOs_kbn_xsrf' + - $ref: '#/components/parameters/SLOs_space_id' + - $ref: '#/components/parameters/SLOs_slo_id' + responses: + '204': + description: Successful request + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_slo_definition_response' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_400_response' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_401_response' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_403_response' + '404': + description: Not found response + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_404_response' + security: + - SLOs_basicAuth: [] + - SLOs_apiKeyAuth: [] + /s/{spaceId}/internal/observability/slos/_historical_summary: + post: + summary: Get a historical summary for SLOs + operationId: historicalSummaryOp + description: > + You must have the `read` privileges for the **SLOs** feature in the + **Observability** section of the Kibana feature privileges. + tags: + - slo + parameters: + - $ref: '#/components/parameters/SLOs_kbn_xsrf' + - $ref: '#/components/parameters/SLOs_space_id' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_historical_summary_request' + responses: + '200': + description: Successful request + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_historical_summary_response' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_400_response' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_401_response' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_403_response' + security: + - SLOs_basicAuth: [] + - SLOs_apiKeyAuth: [] + /s/{spaceId}/internal/observability/slos/_definitions: + get: + summary: Get the SLO definitions + operationId: getDefinitionsOp + description: > + You must have the `read` privileges for the **SLOs** feature in the + **Observability** section of the Kibana feature privileges. + tags: + - slo + parameters: + - $ref: '#/components/parameters/SLOs_kbn_xsrf' + - $ref: '#/components/parameters/SLOs_space_id' + - name: includeOutdatedOnly + in: query + description: >- + Indicates if the API returns only outdated SLO or all SLO + definitions + schema: + type: boolean + example: true + - name: search + in: query + description: Filters the SLOs by name + schema: + type: string + example: my service availability + - name: page + in: query + description: The page to use for pagination, must be greater or equal than 1 + schema: + type: number + example: 1 + - name: perPage + in: query + description: Number of SLOs returned by page + schema: + type: integer + default: 100 + maximum: 1000 + example: 100 + responses: + '200': + description: Successful request + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_find_slo_definitions_response' + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_400_response' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_401_response' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_403_response' + security: + - SLOs_basicAuth: [] + - SLOs_apiKeyAuth: [] + /s/{spaceId}/api/observability/slos/_delete_instances: + post: + summary: Batch delete rollup and summary data + operationId: deleteSloInstancesOp + description: > + The deletion occurs for the specified list of `sloId` and `instanceId`. + You must have `all` privileges for the **SLOs** feature in the + **Observability** section of the Kibana feature privileges. + tags: + - slo + parameters: + - $ref: '#/components/parameters/SLOs_kbn_xsrf' + - $ref: '#/components/parameters/SLOs_space_id' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_delete_slo_instances_request' + responses: + '204': + description: Successful request + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_400_response' + '401': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_401_response' + '403': + description: Unauthorized response + content: + application/json: + schema: + $ref: '#/components/schemas/SLOs_403_response' + servers: + - url: https://localhost:5601 + security: + - SLOs_basicAuth: [] + - SLOs_apiKeyAuth: [] +components: + securitySchemes: + Connectors_basicAuth: + type: http + scheme: basic + Connectors_apiKeyAuth: + type: apiKey + in: header + name: Authorization + description: 'e.g. Authorization: ApiKey base64AccessApiKey' + Data_views_basicAuth: + type: http + scheme: basic + Data_views_apiKeyAuth: + type: apiKey + in: header + name: Authorization + description: > + Serverless APIs support only key-based authentication. You must create + an API key and use the encoded value in the request header. For example: + 'Authorization: ApiKey base64AccessApiKey'. + Machine_learning_APIs_basicAuth: + type: http + scheme: basic + Machine_learning_APIs_apiKeyAuth: + type: apiKey + in: header + name: ApiKey + Saved_objects_basicAuth: + type: http + scheme: basic + Saved_objects_apiKeyAuth: + type: apiKey + in: header + name: Authorization + description: 'e.g. Authorization: ApiKey base64AccessApiKey' + SLOs_basicAuth: + type: http + scheme: basic + SLOs_apiKeyAuth: + type: apiKey + in: header + name: Authorization + description: 'e.g. Authorization: ApiKey base64AccessApiKey' + parameters: + Connectors_kbn_xsrf: + schema: + type: string + in: header + name: kbn-xsrf + description: Cross-site request forgery protection + required: true + Connectors_space_id: + in: path + name: spaceId + description: >- + An identifier for the space. If `/s/` and the identifier are omitted + from the path, the default space is used. + required: true + schema: + type: string + example: default + Connectors_connector_id: + in: path + name: connectorId + description: An identifier for the connector. + required: true + schema: + type: string + example: df770e30-8b8b-11ed-a780-3b746c987a81 + Connectors_action_id: + in: path + name: actionId + description: An identifier for the action. + required: true + schema: + type: string + example: c55b6eb0-6bad-11eb-9f3b-611eebc6c3ad + Data_views_space_id: + in: path + name: spaceId + description: >- + An identifier for the space. If `/s/` and the identifier are omitted + from the path, the default space is used. + required: true + schema: + type: string + example: default + Data_views_kbn_xsrf: + schema: + type: string + in: header + name: kbn-xsrf + description: Cross-site request forgery protection + required: true + Data_views_view_id: + in: path + name: viewId + description: An identifier for the data view. + required: true + schema: + type: string + example: ff959d40-b880-11e8-a6d9-e546fe2bba5f + Data_views_field_name: + in: path + name: fieldName + description: The name of the runtime field. + required: true + schema: + type: string + example: hour_of_day + Machine_learning_APIs_spaceParam: + in: path + name: spaceId + description: >- + An identifier for the space. If `/s/` and the identifier are omitted + from the path, the default space is used. + required: true + schema: + type: string + Machine_learning_APIs_simulateParam: + in: query + name: simulate + description: >- + When true, simulates the synchronization by returning only the list of + actions that would be performed. + required: false + schema: + type: boolean + example: 'true' + Saved_objects_kbn_xsrf: + schema: + type: string + in: header + name: kbn-xsrf + description: Cross-site request forgery protection + required: true + Saved_objects_saved_object_type: + in: path + name: type + description: >- + Valid options include `visualization`, `dashboard`, `search`, + `index-pattern`, `config`. + required: true + schema: + type: string + Saved_objects_saved_object_id: + in: path + name: id + description: An identifier for the saved object. + required: true + schema: + type: string + SLOs_kbn_xsrf: + schema: + type: string + in: header + name: kbn-xsrf + description: Cross-site request forgery protection + required: true + SLOs_space_id: + in: path + name: spaceId + description: >- + An identifier for the space. If `/s/` and the identifier are omitted + from the path, the default space is used. + required: true + schema: + type: string + example: default + SLOs_slo_id: + in: path + name: sloId + description: An identifier for the slo. + required: true + schema: + type: string + example: 9c235211-6834-11ea-a78c-6feb38a34414 + schemas: + Connectors_create_connector_request_bedrock: + title: Create Amazon Bedrock connector request + description: >- + The Amazon Bedrock connector uses axios to send a POST request to Amazon + Bedrock. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_bedrock' + connector_type_id: + type: string + description: The type of connector. + enum: + - .bedrock + example: .bedrock + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_bedrock' + Connectors_create_connector_request_gemini: + title: Create Google Gemini connector request + description: >- + The Google Gemini connector uses axios to send a POST request to Google + Gemini. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_gemini' + connector_type_id: + type: string + description: The type of connector. + enum: + - .gemini + example: .gemini + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_gemini' + Connectors_create_connector_request_cases_webhook: + title: Create Webhook - Case Managment connector request + description: > + The Webhook - Case Management connector uses axios to send POST, PUT, + and GET requests to a case management RESTful API web service. + type: object + required: + - config + - connector_type_id + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_cases_webhook' + connector_type_id: + type: string + description: The type of connector. + enum: + - .cases-webhook + example: .cases-webhook + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_cases_webhook' + Connectors_create_connector_request_d3security: + title: Create D3 Security connector request + description: > + The connector uses axios to send a POST request to a D3 Security + endpoint. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_d3security' + connector_type_id: + type: string + description: The type of connector. + enum: + - .d3security + example: .d3security + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_d3security' + Connectors_create_connector_request_email: + title: Create email connector request + description: > + The email connector uses the SMTP protocol to send mail messages, using + an integration of Nodemailer. An exception is Microsoft Exchange, which + uses HTTP protocol for sending emails, Send mail. Email message text is + sent as both plain text and html text. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_email' + connector_type_id: + type: string + description: The type of connector. + enum: + - .email + example: .email + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_email' + Connectors_create_connector_request_genai: + title: Create OpenAI connector request + description: > + The OpenAI connector uses axios to send a POST request to either OpenAI + or Azure OpenAPI. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_genai' + connector_type_id: + type: string + description: The type of connector. + enum: + - .gen-ai + example: .gen-ai + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_genai' + Connectors_create_connector_request_index: + title: Create index connector request + description: The index connector indexes a document into Elasticsearch. + type: object + required: + - config + - connector_type_id + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_index' + connector_type_id: + type: string + description: The type of connector. + enum: + - .index + example: .index + name: + type: string + description: The display name for the connector. + example: my-connector + Connectors_create_connector_request_jira: + title: Create Jira connector request + description: The Jira connector uses the REST API v2 to create Jira issues. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_jira' + connector_type_id: + type: string + description: The type of connector. + enum: + - .jira + example: .jira + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_jira' + Connectors_create_connector_request_opsgenie: + title: Create Opsgenie connector request + description: The Opsgenie connector uses the Opsgenie alert API. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_opsgenie' + connector_type_id: + type: string + description: The type of connector. + enum: + - .opsgenie + example: .opsgenie + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_opsgenie' + Connectors_create_connector_request_pagerduty: + title: Create PagerDuty connector request + description: > + The PagerDuty connector uses the v2 Events API to trigger, acknowledge, + and resolve PagerDuty alerts. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_pagerduty' + connector_type_id: + type: string + description: The type of connector. + enum: + - .pagerduty + example: .pagerduty + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_pagerduty' + Connectors_create_connector_request_resilient: + title: Create IBM Resilient connector request + description: >- + The IBM Resilient connector uses the RESILIENT REST v2 to create IBM + Resilient incidents. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_resilient' + connector_type_id: + description: The type of connector. + type: string + example: .resilient + enum: + - .resilient + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_resilient' + Connectors_create_connector_request_sentinelone: + title: Create SentinelOne connector request + description: > + The SentinelOne connector communicates with SentinelOne Management + Console via REST API. 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. + x-technical-preview: true + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_sentinelone' + connector_type_id: + type: string + description: The type of connector. + enum: + - .sentinelone + example: .sentinelone + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_sentinelone' + Connectors_create_connector_request_serverlog: + title: Create server log connector request + description: This connector writes an entry to the Kibana server log. + type: object + required: + - connector_type_id + - name + properties: + connector_type_id: + type: string + description: The type of connector. + enum: + - .server-log + example: .server-log + name: + type: string + description: The display name for the connector. + example: my-connector + Connectors_create_connector_request_servicenow: + title: Create ServiceNow ITSM connector request + description: > + The ServiceNow ITSM connector uses the import set API to create + ServiceNow incidents. You can use the connector for rule actions and + cases. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_servicenow' + connector_type_id: + type: string + description: The type of connector. + enum: + - .servicenow + example: .servicenow + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_servicenow' + Connectors_create_connector_request_servicenow_itom: + title: Create ServiceNow ITOM connector request + description: > + The ServiceNow ITOM connector uses the event API to create ServiceNow + events. You can use the connector for rule actions. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_servicenow_itom' + connector_type_id: + type: string + description: The type of connector. + enum: + - .servicenow-itom + example: .servicenow-itom + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_servicenow' + Connectors_create_connector_request_servicenow_sir: + title: Create ServiceNow SecOps connector request + description: > + The ServiceNow SecOps connector uses the import set API to create + ServiceNow security incidents. You can use the connector for rule + actions and cases. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_servicenow' + connector_type_id: + type: string + description: The type of connector. + enum: + - .servicenow-sir + example: .servicenow-sir + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_servicenow' + Connectors_create_connector_request_slack_api: + title: Create Slack connector request + description: The Slack connector uses an API method to send Slack messages. + type: object + required: + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_slack_api' + connector_type_id: + type: string + description: The type of connector. + enum: + - .slack_api + example: .slack_api + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_slack_api' + Connectors_create_connector_request_slack_webhook: + title: Create Slack connector request + description: The Slack connector uses Slack Incoming Webhooks. + type: object + required: + - connector_type_id + - name + - secrets + properties: + connector_type_id: + type: string + description: The type of connector. + enum: + - .slack + example: .slack + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_slack_webhook' + Connectors_create_connector_request_swimlane: + title: Create Swimlane connector request + description: >- + The Swimlane connector uses the Swimlane REST API to create Swimlane + records. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_swimlane' + connector_type_id: + type: string + description: The type of connector. + enum: + - .swimlane + example: .swimlane + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_swimlane' + Connectors_create_connector_request_teams: + title: Create Microsoft Teams connector request + description: The Microsoft Teams connector uses Incoming Webhooks. + type: object + required: + - connector_type_id + - name + - secrets + properties: + connector_type_id: + type: string + description: The type of connector. + enum: + - .teams + example: .teams + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_teams' + Connectors_create_connector_request_tines: + title: Create Tines connector request + description: > + The Tines connector uses Tines Webhook actions to send events via POST + request. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_tines' + connector_type_id: + type: string + description: The type of connector. + enum: + - .tines + example: .tines + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_tines' + Connectors_create_connector_request_torq: + title: Create Torq connector request + description: > + The Torq connector uses a Torq webhook to trigger workflows with Kibana + actions. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_torq' + connector_type_id: + type: string + description: The type of connector. + enum: + - .torq + example: .torq + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_torq' + Connectors_create_connector_request_webhook: + title: Create Webhook connector request + description: > + The Webhook connector uses axios to send a POST or PUT request to a web + service. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_webhook' + connector_type_id: + type: string + description: The type of connector. + enum: + - .webhook + example: .webhook + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_webhook' + Connectors_create_connector_request_xmatters: + title: Create xMatters connector request + description: > + The xMatters connector uses the xMatters Workflow for Elastic to send + actionable alerts to on-call xMatters resources. + type: object + required: + - config + - connector_type_id + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_xmatters' + connector_type_id: + type: string + description: The type of connector. + enum: + - .xmatters + example: .xmatters + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_xmatters' + Connectors_config_properties_bedrock: + title: Connector request properties for an Amazon Bedrock connector + description: Defines properties for connectors when type is `.bedrock`. + type: object + required: + - apiUrl + properties: + apiUrl: + type: string + description: The Amazon Bedrock request URL. + defaultModel: + type: string + description: > + The generative artificial intelligence model for Amazon Bedrock to + use. Current support is for the Anthropic Claude models. + default: anthropic.claude-3-5-sonnet-20240620-v1:0 + Connectors_secrets_properties_bedrock: + title: Connector secrets properties for an Amazon Bedrock connector + description: Defines secrets for connectors when type is `.bedrock`. + type: object + required: + - accessKey + - secret + properties: + accessKey: + type: string + description: The AWS access key for authentication. + secret: + type: string + description: The AWS secret for authentication. + Connectors_config_properties_gemini: + title: Connector request properties for an Google Gemini connector + description: Defines properties for connectors when type is `.gemini`. + type: object + required: + - apiUrl + - gcpRegion + - gcpProjectID + properties: + apiUrl: + type: string + description: The Google Gemini request URL. + defaultModel: + type: string + description: >- + The generative artificial intelligence model for Google Gemini to + use. + default: gemini-1.5-pro-001 + gcpRegion: + type: string + description: The GCP region where the Vertex AI endpoint enabled. + gcpProjectID: + type: string + description: The Google ProjectID that has Vertex AI endpoint enabled. + Connectors_secrets_properties_gemini: + title: Connector secrets properties for a Google Gemini connector + description: Defines secrets for connectors when type is `.gemini`. + type: object + required: + - credentialsJSON + properties: + credentialsJSON: + type: string + description: >- + The service account credentials JSON file. The service account + should have Vertex AI user IAM role assigned to it. + Connectors_config_properties_cases_webhook: + title: Connector request properties for Webhook - Case Management connector + required: + - createIncidentJson + - createIncidentResponseKey + - createIncidentUrl + - getIncidentResponseExternalTitleKey + - getIncidentUrl + - updateIncidentJson + - updateIncidentUrl + - viewIncidentUrl + description: Defines properties for connectors when type is `.cases-webhook`. + type: object + properties: + createCommentJson: + type: string + description: > + A JSON payload sent to the create comment URL to create a case + comment. You can use variables to add Kibana Cases data to the + payload. The required variable is `case.comment`. Due to Mustache + template variables (the text enclosed in triple braces, for example, + `{{{case.title}}}`), the JSON is not validated when you create the + connector. The JSON is validated once the Mustache variables have + been placed when the REST method runs. Manually ensure that the JSON + is valid, disregarding the Mustache variables, so the later + validation will pass. + example: '{"body": {{{case.comment}}}}' + createCommentMethod: + type: string + description: > + The REST API HTTP request method to create a case comment in the + third-party system. Valid values are `patch`, `post`, and `put`. + default: put + enum: + - patch + - post + - put + createCommentUrl: + type: string + description: > + The REST API URL to create a case comment by ID in the third-party + system. You can use a variable to add the external system ID to the + URL. If you are using the `xpack.actions.allowedHosts setting`, add + the hostname to the allowed hosts. + example: https://example.com/issue/{{{external.system.id}}}/comment + createIncidentJson: + type: string + description: > + A JSON payload sent to the create case URL to create a case. You can + use variables to add case data to the payload. Required variables + are `case.title` and `case.description`. Due to Mustache template + variables (which is the text enclosed in triple braces, for example, + `{{{case.title}}}`), the JSON is not validated when you create the + connector. The JSON is validated after the Mustache variables have + been placed when REST method runs. Manually ensure that the JSON is + valid to avoid future validation errors; disregard Mustache + variables during your review. + example: >- + {"fields": {"summary": {{{case.title}}},"description": + {{{case.description}}},"labels": {{{case.tags}}}}} + createIncidentMethod: + type: string + description: > + The REST API HTTP request method to create a case in the third-party + system. Valid values are `patch`, `post`, and `put`. + enum: + - patch + - post + - put + default: post + createIncidentResponseKey: + type: string + description: >- + The JSON key in the create external case response that contains the + case ID. + createIncidentUrl: + type: string + description: > + The REST API URL to create a case in the third-party system. If you + are using the `xpack.actions.allowedHosts` setting, add the hostname + to the allowed hosts. + getIncidentResponseExternalTitleKey: + type: string + description: >- + The JSON key in get external case response that contains the case + title. + getIncidentUrl: + type: string + description: > + The REST API URL to get the case by ID from the third-party system. + If you are using the `xpack.actions.allowedHosts` setting, add the + hostname to the allowed hosts. You can use a variable to add the + external system ID to the URL. Due to Mustache template variables + (the text enclosed in triple braces, for example, + `{{{case.title}}}`), the JSON is not validated when you create the + connector. The JSON is validated after the Mustache variables have + been placed when REST method runs. Manually ensure that the JSON is + valid, disregarding the Mustache variables, so the later validation + will pass. + example: https://example.com/issue/{{{external.system.id}}} + hasAuth: + type: boolean + description: >- + If true, a username and password for login type authentication must + be provided. + default: true + headers: + type: string + description: > + A set of key-value pairs sent as headers with the request URLs for + the create case, update case, get case, and create comment methods. + updateIncidentJson: + type: string + description: > + The JSON payload sent to the update case URL to update the case. You + can use variables to add Kibana Cases data to the payload. Required + variables are `case.title` and `case.description`. Due to Mustache + template variables (which is the text enclosed in triple braces, for + example, `{{{case.title}}}`), the JSON is not validated when you + create the connector. The JSON is validated after the Mustache + variables have been placed when REST method runs. Manually ensure + that the JSON is valid to avoid future validation errors; disregard + Mustache variables during your review. + example: >- + {"fields": {"summary": {{{case.title}}},"description": + {{{case.description}}},"labels": {{{case.tags}}}}} + updateIncidentMethod: + type: string + description: > + The REST API HTTP request method to update the case in the + third-party system. Valid values are `patch`, `post`, and `put`. + default: put + enum: + - patch + - post + - put + updateIncidentUrl: + type: string + description: > + The REST API URL to update the case by ID in the third-party system. + You can use a variable to add the external system ID to the URL. If + you are using the `xpack.actions.allowedHosts` setting, add the + hostname to the allowed hosts. + example: https://example.com/issue/{{{external.system.ID}}} + viewIncidentUrl: + type: string + description: > + The URL to view the case in the external system. You can use + variables to add the external system ID or external system title to + the URL. + example: >- + https://testing-jira.atlassian.net/browse/{{{external.system.title}}} + Connectors_secrets_properties_cases_webhook: + title: Connector secrets properties for Webhook - Case Management connector + type: object + properties: + password: + type: string + description: >- + The password for HTTP basic authentication. If `hasAuth` is set to + `true`, this property is required. + user: + type: string + description: >- + The username for HTTP basic authentication. If `hasAuth` is set to + `true`, this property is required. + Connectors_config_properties_d3security: + title: Connector request properties for a D3 Security connector + description: Defines properties for connectors when type is `.d3security`. + type: object + required: + - url + properties: + url: + type: string + description: > + The D3 Security API request URL. If you are using the + `xpack.actions.allowedHosts` setting, add the hostname to the + allowed hosts. + Connectors_secrets_properties_d3security: + title: Connector secrets properties for a D3 Security connector + description: Defines secrets for connectors when type is `.d3security`. + required: + - token + type: object + properties: + token: + type: string + description: The D3 Security token. + Connectors_config_properties_email: + title: Connector request properties for an email connector + description: Defines properties for connectors when type is `.email`. + required: + - from + type: object + properties: + clientId: + description: > + The client identifier, which is a part of OAuth 2.0 client + credentials authentication, in GUID format. If `service` is + `exchange_server`, this property is required. + type: string + nullable: true + from: + description: > + The from address for all emails sent by the connector. It must be + specified in `user@host-name` format. + type: string + hasAuth: + description: > + Specifies whether a user and password are required inside the + secrets configuration. + default: true + type: boolean + host: + description: > + The host name of the service provider. If the `service` is + `elastic_cloud` (for Elastic Cloud notifications) or one of + Nodemailer's well-known email service providers, this property is + ignored. If `service` is `other`, this property must be defined. + type: string + oauthTokenUrl: + type: string + nullable: true + port: + description: > + The port to connect to on the service provider. If the `service` is + `elastic_cloud` (for Elastic Cloud notifications) or one of + Nodemailer's well-known email service providers, this property is + ignored. If `service` is `other`, this property must be defined. + type: integer + secure: + description: > + Specifies whether the connection to the service provider will use + TLS. If the `service` is `elastic_cloud` (for Elastic Cloud + notifications) or one of Nodemailer's well-known email service + providers, this property is ignored. + type: boolean + service: + description: | + The name of the email service. + type: string + enum: + - elastic_cloud + - exchange_server + - gmail + - other + - outlook365 + - ses + tenantId: + description: > + The tenant identifier, which is part of OAuth 2.0 client credentials + authentication, in GUID format. If `service` is `exchange_server`, + this property is required. + type: string + nullable: true + Connectors_secrets_properties_email: + title: Connector secrets properties for an email connector + description: Defines secrets for connectors when type is `.email`. + type: object + properties: + clientSecret: + type: string + description: > + The Microsoft Exchange Client secret for OAuth 2.0 client + credentials authentication. It must be URL-encoded. If `service` is + `exchange_server`, this property is required. + password: + type: string + description: > + The password for HTTP basic authentication. If `hasAuth` is set to + `true`, this property is required. + user: + type: string + description: > + The username for HTTP basic authentication. If `hasAuth` is set to + `true`, this property is required. + Connectors_config_properties_genai_azure: + title: >- + Connector request properties for an OpenAI connector that uses Azure + OpenAI + description: > + Defines properties for connectors when type is `.gen-ai` and the API + provider is `Azure OpenAI'. + type: object + required: + - apiProvider + - apiUrl + properties: + apiProvider: + type: string + description: The OpenAI API provider. + enum: + - Azure OpenAI + apiUrl: + type: string + description: The OpenAI API endpoint. + Connectors_config_properties_genai_openai: + title: Connector request properties for an OpenAI connector + description: > + Defines properties for connectors when type is `.gen-ai` and the API + provider is `OpenAI'. + type: object + required: + - apiProvider + - apiUrl + properties: + apiProvider: + type: string + description: The OpenAI API provider. + enum: + - OpenAI + apiUrl: + type: string + description: The OpenAI API endpoint. + defaultModel: + type: string + description: The default model to use for requests. + Connectors_config_properties_genai: + title: Connector request properties for an OpenAI connector + description: Defines properties for connectors when type is `.gen-ai`. + oneOf: + - $ref: '#/components/schemas/Connectors_config_properties_genai_azure' + - $ref: '#/components/schemas/Connectors_config_properties_genai_openai' + discriminator: + propertyName: apiProvider + mapping: + Azure OpenAI: '#/components/schemas/Connectors_config_properties_genai_azure' + OpenAI: '#/components/schemas/Connectors_config_properties_genai_openai' + Connectors_secrets_properties_genai: + title: Connector secrets properties for an OpenAI connector + description: Defines secrets for connectors when type is `.gen-ai`. + type: object + properties: + apiKey: + type: string + description: The OpenAI API key. + Connectors_config_properties_index: + title: Connector request properties for an index connector + required: + - index + description: Defines properties for connectors when type is `.index`. + type: object + properties: + executionTimeField: + description: A field that indicates when the document was indexed. + default: null + type: string + nullable: true + index: + description: The Elasticsearch index to be written to. + type: string + refresh: + description: > + The refresh policy for the write request, which affects when changes + are made visible to search. Refer to the refresh setting for + Elasticsearch document APIs. + default: false + type: boolean + Connectors_config_properties_jira: + title: Connector request properties for a Jira connector + required: + - apiUrl + - projectKey + description: Defines properties for connectors when type is `.jira`. + type: object + properties: + apiUrl: + description: The Jira instance URL. + type: string + projectKey: + description: The Jira project key. + type: string + Connectors_secrets_properties_jira: + title: Connector secrets properties for a Jira connector + required: + - apiToken + - email + description: Defines secrets for connectors when type is `.jira`. + type: object + properties: + apiToken: + description: The Jira API authentication token for HTTP basic authentication. + type: string + email: + description: The account email for HTTP Basic authentication. + type: string + Connectors_config_properties_opsgenie: + title: Connector request properties for an Opsgenie connector + required: + - apiUrl + description: Defines properties for connectors when type is `.opsgenie`. + type: object + properties: + apiUrl: + description: > + The Opsgenie URL. For example, `https://api.opsgenie.com` or + `https://api.eu.opsgenie.com`. If you are using the + `xpack.actions.allowedHosts` setting, add the hostname to the + allowed hosts. + type: string + Connectors_secrets_properties_opsgenie: + title: Connector secrets properties for an Opsgenie connector + required: + - apiKey + description: Defines secrets for connectors when type is `.opsgenie`. + type: object + properties: + apiKey: + description: The Opsgenie API authentication key for HTTP Basic authentication. + type: string + Connectors_config_properties_pagerduty: + title: Connector request properties for a PagerDuty connector + description: Defines properties for connectors when type is `.pagerduty`. + type: object + properties: + apiUrl: + description: The PagerDuty event URL. + type: string + nullable: true + example: https://events.pagerduty.com/v2/enqueue + Connectors_secrets_properties_pagerduty: + title: Connector secrets properties for a PagerDuty connector + description: Defines secrets for connectors when type is `.pagerduty`. + type: object + required: + - routingKey + properties: + routingKey: + description: > + A 32 character PagerDuty Integration Key for an integration on a + service. + type: string + Connectors_config_properties_resilient: + title: Connector request properties for a IBM Resilient connector + required: + - apiUrl + - orgId + description: Defines properties for connectors when type is `.resilient`. + type: object + properties: + apiUrl: + description: The IBM Resilient instance URL. + type: string + orgId: + description: The IBM Resilient organization ID. + type: string + Connectors_secrets_properties_resilient: + title: Connector secrets properties for IBM Resilient connector + required: + - apiKeyId + - apiKeySecret + description: Defines secrets for connectors when type is `.resilient`. + type: object + properties: + apiKeyId: + type: string + description: The authentication key ID for HTTP Basic authentication. + apiKeySecret: + type: string + description: The authentication key secret for HTTP Basic authentication. + Connectors_config_properties_sentinelone: + title: Connector request properties for a SentinelOne connector + required: + - url + description: Defines properties for connectors when type is `.sentinelone`. + type: object + properties: + url: + description: > + The SentinelOne tenant URL. If you are using the + `xpack.actions.allowedHosts` setting, add the hostname to the + allowed hosts. + type: string + Connectors_secrets_properties_sentinelone: + title: Connector secrets properties for a SentinelOne connector + description: Defines secrets for connectors when type is `.sentinelone`. + type: object + required: + - token + properties: + token: + description: The A SentinelOne API token. + type: string + Connectors_config_properties_servicenow: + title: Connector request properties for a ServiceNow ITSM connector + required: + - apiUrl + description: Defines properties for connectors when type is `.servicenow`. + type: object + properties: + apiUrl: + type: string + description: The ServiceNow instance URL. + clientId: + description: > + The client ID assigned to your OAuth application. This property is + required when `isOAuth` is `true`. + type: string + isOAuth: + description: > + The type of authentication to use. The default value is false, which + means basic authentication is used instead of open authorization + (OAuth). + default: false + type: boolean + jwtKeyId: + description: > + The key identifier assigned to the JWT verifier map of your OAuth + application. This property is required when `isOAuth` is `true`. + type: string + userIdentifierValue: + description: > + The identifier to use for OAuth authentication. This identifier + should be the user field you selected when you created an OAuth JWT + API endpoint for external clients in your ServiceNow instance. For + example, if the selected user field is `Email`, the user identifier + should be the user's email address. This property is required when + `isOAuth` is `true`. + type: string + usesTableApi: + description: > + Determines whether the connector uses the Table API or the Import + Set API. This property is supported only for ServiceNow ITSM and + ServiceNow SecOps connectors. NOTE: If this property is set to + `false`, the Elastic application should be installed in ServiceNow. + default: true + type: boolean + Connectors_secrets_properties_servicenow: + title: >- + Connector secrets properties for ServiceNow ITOM, ServiceNow ITSM, and + ServiceNow SecOps connectors + description: >- + Defines secrets for connectors when type is `.servicenow`, + `.servicenow-sir`, or `.servicenow-itom`. + type: object + properties: + clientSecret: + type: string + description: >- + The client secret assigned to your OAuth application. This property + is required when `isOAuth` is `true`. + password: + type: string + description: >- + The password for HTTP basic authentication. This property is + required when `isOAuth` is `false`. + privateKey: + type: string + description: >- + The RSA private key that you created for use in ServiceNow. This + property is required when `isOAuth` is `true`. + privateKeyPassword: + type: string + description: >- + The password for the RSA private key. This property is required when + `isOAuth` is `true` and you set a password on your private key. + username: + type: string + description: >- + The username for HTTP basic authentication. This property is + required when `isOAuth` is `false`. + Connectors_config_properties_servicenow_itom: + title: Connector request properties for a ServiceNow ITSM connector + required: + - apiUrl + description: Defines properties for connectors when type is `.servicenow`. + type: object + properties: + apiUrl: + type: string + description: The ServiceNow instance URL. + clientId: + description: > + The client ID assigned to your OAuth application. This property is + required when `isOAuth` is `true`. + type: string + isOAuth: + description: > + The type of authentication to use. The default value is false, which + means basic authentication is used instead of open authorization + (OAuth). + default: false + type: boolean + jwtKeyId: + description: > + The key identifier assigned to the JWT verifier map of your OAuth + application. This property is required when `isOAuth` is `true`. + type: string + userIdentifierValue: + description: > + The identifier to use for OAuth authentication. This identifier + should be the user field you selected when you created an OAuth JWT + API endpoint for external clients in your ServiceNow instance. For + example, if the selected user field is `Email`, the user identifier + should be the user's email address. This property is required when + `isOAuth` is `true`. + type: string + Connectors_config_properties_slack_api: + title: Connector request properties for a Slack connector + description: Defines properties for connectors when type is `.slack_api`. + type: object + properties: + allowedChannels: + type: array + description: A list of valid Slack channels. + items: + type: object + required: + - id + - name + maxItems: 25 + properties: + id: + type: string + description: The Slack channel ID. + example: C123ABC456 + minLength: 1 + name: + type: string + description: The Slack channel name. + minLength: 1 + Connectors_secrets_properties_slack_api: + title: Connector secrets properties for a Web API Slack connector + description: Defines secrets for connectors when type is `.slack`. + required: + - token + type: object + properties: + token: + type: string + description: Slack bot user OAuth token. + Connectors_secrets_properties_slack_webhook: + title: Connector secrets properties for a Webhook Slack connector + description: Defines secrets for connectors when type is `.slack`. + required: + - webhookUrl + type: object + properties: + webhookUrl: + type: string + description: Slack webhook url. + Connectors_config_properties_swimlane: + title: Connector request properties for a Swimlane connector + required: + - apiUrl + - appId + - connectorType + description: Defines properties for connectors when type is `.swimlane`. + type: object + properties: + apiUrl: + description: The Swimlane instance URL. + type: string + appId: + description: The Swimlane application ID. + type: string + connectorType: + description: >- + The type of connector. Valid values are `all`, `alerts`, and + `cases`. + type: string + enum: + - all + - alerts + - cases + mappings: + title: Connector mappings properties for a Swimlane connector + description: The field mapping. + type: object + properties: + alertIdConfig: + title: Alert identifier mapping + description: Mapping for the alert ID. + type: object + required: + - fieldType + - id + - key + - name + properties: + fieldType: + type: string + description: The type of field in Swimlane. + id: + type: string + description: The identifier for the field in Swimlane. + key: + type: string + description: The key for the field in Swimlane. + name: + type: string + description: The name of the field in Swimlane. + caseIdConfig: + title: Case identifier mapping + description: Mapping for the case ID. + type: object + required: + - fieldType + - id + - key + - name + properties: + fieldType: + type: string + description: The type of field in Swimlane. + id: + type: string + description: The identifier for the field in Swimlane. + key: + type: string + description: The key for the field in Swimlane. + name: + type: string + description: The name of the field in Swimlane. + caseNameConfig: + title: Case name mapping + description: Mapping for the case name. + type: object + required: + - fieldType + - id + - key + - name + properties: + fieldType: + type: string + description: The type of field in Swimlane. + id: + type: string + description: The identifier for the field in Swimlane. + key: + type: string + description: The key for the field in Swimlane. + name: + type: string + description: The name of the field in Swimlane. + commentsConfig: + title: Case comment mapping + description: Mapping for the case comments. + type: object + required: + - fieldType + - id + - key + - name + properties: + fieldType: + type: string + description: The type of field in Swimlane. + id: + type: string + description: The identifier for the field in Swimlane. + key: + type: string + description: The key for the field in Swimlane. + name: + type: string + description: The name of the field in Swimlane. + descriptionConfig: + title: Case description mapping + description: Mapping for the case description. + type: object + required: + - fieldType + - id + - key + - name + properties: + fieldType: + type: string + description: The type of field in Swimlane. + id: + type: string + description: The identifier for the field in Swimlane. + key: + type: string + description: The key for the field in Swimlane. + name: + type: string + description: The name of the field in Swimlane. + ruleNameConfig: + title: Rule name mapping + description: Mapping for the name of the alert's rule. + type: object + required: + - fieldType + - id + - key + - name + properties: + fieldType: + type: string + description: The type of field in Swimlane. + id: + type: string + description: The identifier for the field in Swimlane. + key: + type: string + description: The key for the field in Swimlane. + name: + type: string + description: The name of the field in Swimlane. + severityConfig: + title: Severity mapping + description: Mapping for the severity. + type: object + required: + - fieldType + - id + - key + - name + properties: + fieldType: + type: string + description: The type of field in Swimlane. + id: + type: string + description: The identifier for the field in Swimlane. + key: + type: string + description: The key for the field in Swimlane. + name: + type: string + description: The name of the field in Swimlane. + Connectors_secrets_properties_swimlane: + title: Connector secrets properties for a Swimlane connector + description: Defines secrets for connectors when type is `.swimlane`. + type: object + properties: + apiToken: + description: Swimlane API authentication token. + type: string + Connectors_secrets_properties_teams: + title: Connector secrets properties for a Microsoft Teams connector + description: Defines secrets for connectors when type is `.teams`. + type: object + required: + - webhookUrl + properties: + webhookUrl: + type: string + description: > + The URL of the incoming webhook. If you are using the + `xpack.actions.allowedHosts` setting, add the hostname to the + allowed hosts. + Connectors_config_properties_tines: + title: Connector request properties for a Tines connector + description: Defines properties for connectors when type is `.tines`. + type: object + required: + - url + properties: + url: + description: > + The Tines tenant URL. If you are using the + `xpack.actions.allowedHosts` setting, make sure this hostname is + added to the allowed hosts. + type: string + Connectors_secrets_properties_tines: + title: Connector secrets properties for a Tines connector + description: Defines secrets for connectors when type is `.tines`. + type: object + required: + - email + - token + properties: + email: + description: The email used to sign in to Tines. + type: string + token: + description: The Tines API token. + type: string + Connectors_config_properties_torq: + title: Connector request properties for a Torq connector + description: Defines properties for connectors when type is `.torq`. + type: object + required: + - webhookIntegrationUrl + properties: + webhookIntegrationUrl: + description: The endpoint URL of the Elastic Security integration in Torq. + type: string + Connectors_secrets_properties_torq: + title: Connector secrets properties for a Torq connector + description: Defines secrets for connectors when type is `.torq`. + type: object + required: + - token + properties: + token: + description: The secret of the webhook authentication header. + type: string + Connectors_config_properties_webhook: + title: Connector request properties for a Webhook connector + description: Defines properties for connectors when type is `.webhook`. + type: object + properties: + authType: + type: string + nullable: true + enum: + - webhook-authentication-basic + - webhook-authentication-ssl + description: | + The type of authentication to use: basic, SSL, or none. + ca: + type: string + description: > + A base64 encoded version of the certificate authority file that the + connector can trust to sign and validate certificates. This option + is available for all authentication types. + certType: + type: string + description: > + If the `authType` is `webhook-authentication-ssl`, specifies whether + the certificate authentication data is in a CRT and key file format + or a PFX file format. + enum: + - ssl-crt-key + - ssl-pfx + hasAuth: + type: boolean + description: > + If `true`, a user name and password must be provided for login type + authentication. + headers: + type: object + nullable: true + description: A set of key-value pairs sent as headers with the request. + method: + type: string + default: post + enum: + - post + - put + description: | + The HTTP request method, either `post` or `put`. + url: + type: string + description: > + The request URL. If you are using the `xpack.actions.allowedHosts` + setting, add the hostname to the allowed hosts. + verificationMode: + type: string + enum: + - certificate + - full + - none + default: full + description: > + Controls the verification of certificates. Use `full` to validate + that the certificate has an issue date within the `not_before` and + `not_after` dates, chains to a trusted certificate authority (CA), + and has a hostname or IP address that matches the names within the + certificate. Use `certificate` to validate the certificate and + verify that it is signed by a trusted authority; this option does + not check the certificate hostname. Use `none` to skip certificate + validation. + Connectors_secrets_properties_webhook: + title: Connector secrets properties for a Webhook connector + description: Defines secrets for connectors when type is `.webhook`. + type: object + properties: + crt: + type: string + description: >- + If `authType` is `webhook-authentication-ssl` and `certType` is + `ssl-crt-key`, it is a base64 encoded version of the CRT or CERT + file. + key: + type: string + description: >- + If `authType` is `webhook-authentication-ssl` and `certType` is + `ssl-crt-key`, it is a base64 encoded version of the KEY file. + pfx: + type: string + description: >- + If `authType` is `webhook-authentication-ssl` and `certType` is + `ssl-pfx`, it is a base64 encoded version of the PFX or P12 file. + password: + type: string + description: > + The password for HTTP basic authentication or the passphrase for the + SSL certificate files. If `hasAuth` is set to `true` and `authType` + is `webhook-authentication-basic`, this property is required. + user: + type: string + description: > + The username for HTTP basic authentication. If `hasAuth` is set to + `true` and `authType` is `webhook-authentication-basic`, this + property is required. + Connectors_config_properties_xmatters: + title: Connector request properties for an xMatters connector + description: Defines properties for connectors when type is `.xmatters`. + type: object + properties: + configUrl: + description: > + The request URL for the Elastic Alerts trigger in xMatters. It is + applicable only when `usesBasic` is `true`. + type: string + nullable: true + usesBasic: + description: >- + Specifies whether the connector uses HTTP basic authentication + (`true`) or URL authentication (`false`). + type: boolean + default: true + Connectors_secrets_properties_xmatters: + title: Connector secrets properties for an xMatters connector + description: Defines secrets for connectors when type is `.xmatters`. + type: object + properties: + password: + description: > + A user name for HTTP basic authentication. It is applicable only + when `usesBasic` is `true`. + type: string + secretsUrl: + description: > + The request URL for the Elastic Alerts trigger in xMatters with the + API key included in the URL. It is applicable only when `usesBasic` + is `false`. + type: string + user: + description: > + A password for HTTP basic authentication. It is applicable only when + `usesBasic` is `true`. + type: string + Connectors_create_connector_request: + title: Create connector request body properties + description: The properties vary depending on the connector type. + oneOf: + - $ref: '#/components/schemas/Connectors_create_connector_request_bedrock' + - $ref: '#/components/schemas/Connectors_create_connector_request_gemini' + - $ref: >- + #/components/schemas/Connectors_create_connector_request_cases_webhook + - $ref: '#/components/schemas/Connectors_create_connector_request_d3security' + - $ref: '#/components/schemas/Connectors_create_connector_request_email' + - $ref: '#/components/schemas/Connectors_create_connector_request_genai' + - $ref: '#/components/schemas/Connectors_create_connector_request_index' + - $ref: '#/components/schemas/Connectors_create_connector_request_jira' + - $ref: '#/components/schemas/Connectors_create_connector_request_opsgenie' + - $ref: '#/components/schemas/Connectors_create_connector_request_pagerduty' + - $ref: '#/components/schemas/Connectors_create_connector_request_resilient' + - $ref: '#/components/schemas/Connectors_create_connector_request_sentinelone' + - $ref: '#/components/schemas/Connectors_create_connector_request_serverlog' + - $ref: '#/components/schemas/Connectors_create_connector_request_servicenow' + - $ref: >- + #/components/schemas/Connectors_create_connector_request_servicenow_itom + - $ref: >- + #/components/schemas/Connectors_create_connector_request_servicenow_sir + - $ref: '#/components/schemas/Connectors_create_connector_request_slack_api' + - $ref: >- + #/components/schemas/Connectors_create_connector_request_slack_webhook + - $ref: '#/components/schemas/Connectors_create_connector_request_swimlane' + - $ref: '#/components/schemas/Connectors_create_connector_request_teams' + - $ref: '#/components/schemas/Connectors_create_connector_request_tines' + - $ref: '#/components/schemas/Connectors_create_connector_request_torq' + - $ref: '#/components/schemas/Connectors_create_connector_request_webhook' + - $ref: '#/components/schemas/Connectors_create_connector_request_xmatters' + discriminator: + propertyName: connector_type_id + mapping: + .bedrock: '#/components/schemas/Connectors_create_connector_request_bedrock' + .gemini: '#/components/schemas/Connectors_create_connector_request_gemini' + .cases-webhook: >- + #/components/schemas/Connectors_create_connector_request_cases_webhook + .d3security: '#/components/schemas/Connectors_create_connector_request_d3security' + .email: '#/components/schemas/Connectors_create_connector_request_email' + .gen-ai: '#/components/schemas/Connectors_create_connector_request_genai' + .index: '#/components/schemas/Connectors_create_connector_request_index' + .jira: '#/components/schemas/Connectors_create_connector_request_jira' + .opsgenie: '#/components/schemas/Connectors_create_connector_request_opsgenie' + .pagerduty: '#/components/schemas/Connectors_create_connector_request_pagerduty' + .resilient: '#/components/schemas/Connectors_create_connector_request_resilient' + .sentinelone: '#/components/schemas/Connectors_create_connector_request_sentinelone' + .server-log: '#/components/schemas/Connectors_create_connector_request_serverlog' + .servicenow: '#/components/schemas/Connectors_create_connector_request_servicenow' + .servicenow-itom: >- + #/components/schemas/Connectors_create_connector_request_servicenow_itom + .servicenow-sir: >- + #/components/schemas/Connectors_create_connector_request_servicenow_sir + .slack_api: '#/components/schemas/Connectors_create_connector_request_slack_api' + .slack: >- + #/components/schemas/Connectors_create_connector_request_slack_webhook + .swimlane: '#/components/schemas/Connectors_create_connector_request_swimlane' + .teams: '#/components/schemas/Connectors_create_connector_request_teams' + .tines: '#/components/schemas/Connectors_create_connector_request_tines' + .torq: '#/components/schemas/Connectors_create_connector_request_torq' + .webhook: '#/components/schemas/Connectors_create_connector_request_webhook' + .xmatters: '#/components/schemas/Connectors_create_connector_request_xmatters' + Connectors_connector_response_properties_bedrock: + title: Connector response properties for an Amazon Bedrock connector + type: object + required: + - config + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_bedrock' + connector_type_id: + type: string + description: The type of connector. + enum: + - .bedrock + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + Connectors_connector_response_properties_gemini: + title: Connector response properties for a Google Gemini connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_gemini' + connector_type_id: + type: string + description: The type of connector. + enum: + - .gemini + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_cases_webhook: + title: Connector request properties for a Webhook - Case Management connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_cases_webhook' + connector_type_id: + description: The type of connector. + type: string + enum: + - .cases-webhook + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_d3security: + title: Connector response properties for a D3 Security connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_d3security' + connector_type_id: + type: string + description: The type of connector. + enum: + - .d3security + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_email: + title: Connector response properties for an email connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_email' + connector_type_id: + type: string + description: The type of connector. + enum: + - .email + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_genai: + title: Connector response properties for an OpenAI connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_genai' + connector_type_id: + type: string + description: The type of connector. + enum: + - .gen-ai + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_index: + title: Connector response properties for an index connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_index' + connector_type_id: + type: string + description: The type of connector. + enum: + - .index + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_jira: + title: Connector response properties for a Jira connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_jira' + connector_type_id: + type: string + description: The type of connector. + enum: + - .jira + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_opsgenie: + title: Connector response properties for an Opsgenie connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_opsgenie' + connector_type_id: + type: string + description: The type of connector. + enum: + - .opsgenie + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_pagerduty: + title: Connector response properties for a PagerDuty connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_pagerduty' + connector_type_id: + type: string + description: The type of connector. + enum: + - .pagerduty + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_resilient: + title: Connector response properties for a IBM Resilient connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_resilient' + connector_type_id: + type: string + description: The type of connector. + enum: + - .resilient + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_sentinelone: + title: Connector response properties for a SentinelOne connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_sentinelone' + connector_type_id: + type: string + description: The type of connector. + enum: + - .sentinelone + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_serverlog: + title: Connector response properties for a server log connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + type: object + nullable: true + connector_type_id: + type: string + description: The type of connector. + enum: + - .server-log + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_servicenow: + title: Connector response properties for a ServiceNow ITSM connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_servicenow' + connector_type_id: + type: string + description: The type of connector. + enum: + - .servicenow + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_servicenow_itom: + title: Connector response properties for a ServiceNow ITOM connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_servicenow_itom' + connector_type_id: + type: string + description: The type of connector. + enum: + - .servicenow-itom + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_servicenow_sir: + title: Connector response properties for a ServiceNow SecOps connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_servicenow' + connector_type_id: + type: string + description: The type of connector. + enum: + - .servicenow-sir + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_slack_api: + title: Connector response properties for a Slack connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_slack_api' + connector_type_id: + type: string + description: The type of connector. + enum: + - .slack_api + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_slack_webhook: + title: Connector response properties for a Slack connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + connector_type_id: + type: string + description: The type of connector. + enum: + - .slack + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_swimlane: + title: Connector response properties for a Swimlane connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_swimlane' + connector_type_id: + type: string + description: The type of connector. + enum: + - .swimlane + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_teams: + title: Connector response properties for a Microsoft Teams connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + type: object + connector_type_id: + type: string + description: The type of connector. + enum: + - .teams + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_tines: + title: Connector response properties for a Tines connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_tines' + connector_type_id: + type: string + description: The type of connector. + enum: + - .tines + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_torq: + title: Connector response properties for a Torq connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_torq' + connector_type_id: + type: string + description: The type of connector. + enum: + - .torq + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_webhook: + title: Connector response properties for a Webhook connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_webhook' + connector_type_id: + type: string + description: The type of connector. + enum: + - .webhook + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_connector_response_properties_xmatters: + title: Connector response properties for an xMatters connector + type: object + required: + - connector_type_id + - id + - is_deprecated + - is_preconfigured + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_xmatters' + connector_type_id: + type: string + description: The type of connector. + enum: + - .xmatters + id: + type: string + description: The identifier for the connector. + is_deprecated: + $ref: '#/components/schemas/Connectors_is_deprecated' + is_missing_secrets: + $ref: '#/components/schemas/Connectors_is_missing_secrets' + is_preconfigured: + $ref: '#/components/schemas/Connectors_is_preconfigured' + is_system_action: + $ref: '#/components/schemas/Connectors_is_system_action' + name: + type: string + description: The display name for the connector. + referenced_by_count: + $ref: '#/components/schemas/Connectors_referenced_by_count' + Connectors_is_deprecated: + type: boolean + description: Indicates whether the connector type is deprecated. + example: false + Connectors_is_missing_secrets: + type: boolean + description: >- + Indicates whether secrets are missing for the connector. Secrets + configuration properties vary depending on the connector type. + example: false + Connectors_is_preconfigured: + type: boolean + description: > + Indicates whether it is a preconfigured connector. If true, the `config` + and `is_missing_secrets` properties are omitted from the response. + example: false + Connectors_is_system_action: + type: boolean + description: Indicates whether the connector is used for system actions. + example: false + Connectors_referenced_by_count: + type: integer + description: > + Indicates the number of saved objects that reference the connector. If + `is_preconfigured` is true, this value is not calculated. This property + is returned only by the get all connectors API. + example: 2 + Connectors_connector_response_properties: + title: Connector response properties + description: The properties vary depending on the connector type. + oneOf: + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_bedrock + - $ref: '#/components/schemas/Connectors_connector_response_properties_gemini' + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_cases_webhook + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_d3security + - $ref: '#/components/schemas/Connectors_connector_response_properties_email' + - $ref: '#/components/schemas/Connectors_connector_response_properties_genai' + - $ref: '#/components/schemas/Connectors_connector_response_properties_index' + - $ref: '#/components/schemas/Connectors_connector_response_properties_jira' + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_opsgenie + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_pagerduty + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_resilient + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_sentinelone + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_serverlog + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_servicenow + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_servicenow_itom + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_servicenow_sir + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_slack_api + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_slack_webhook + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_swimlane + - $ref: '#/components/schemas/Connectors_connector_response_properties_teams' + - $ref: '#/components/schemas/Connectors_connector_response_properties_tines' + - $ref: '#/components/schemas/Connectors_connector_response_properties_torq' + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_webhook + - $ref: >- + #/components/schemas/Connectors_connector_response_properties_xmatters + discriminator: + propertyName: connector_type_id + mapping: + .bedrock: >- + #/components/schemas/Connectors_connector_response_properties_bedrock + .gemini: '#/components/schemas/Connectors_connector_response_properties_gemini' + .cases-webhook: >- + #/components/schemas/Connectors_connector_response_properties_cases_webhook + .d3security: >- + #/components/schemas/Connectors_connector_response_properties_d3security + .email: '#/components/schemas/Connectors_connector_response_properties_email' + .gen-ai: '#/components/schemas/Connectors_connector_response_properties_genai' + .index: '#/components/schemas/Connectors_connector_response_properties_index' + .jira: '#/components/schemas/Connectors_connector_response_properties_jira' + .opsgenie: >- + #/components/schemas/Connectors_connector_response_properties_opsgenie + .pagerduty: >- + #/components/schemas/Connectors_connector_response_properties_pagerduty + .resilient: >- + #/components/schemas/Connectors_connector_response_properties_resilient + .sentinelone: >- + #/components/schemas/Connectors_connector_response_properties_sentinelone + .server-log: >- + #/components/schemas/Connectors_connector_response_properties_serverlog + .servicenow: >- + #/components/schemas/Connectors_connector_response_properties_servicenow + .servicenow-itom: >- + #/components/schemas/Connectors_connector_response_properties_servicenow_itom + .servicenow-sir: >- + #/components/schemas/Connectors_connector_response_properties_servicenow_sir + .slack_api: >- + #/components/schemas/Connectors_connector_response_properties_slack_api + .slack: >- + #/components/schemas/Connectors_connector_response_properties_slack_webhook + .swimlane: >- + #/components/schemas/Connectors_connector_response_properties_swimlane + .teams: '#/components/schemas/Connectors_connector_response_properties_teams' + .tines: '#/components/schemas/Connectors_connector_response_properties_tines' + .torq: '#/components/schemas/Connectors_connector_response_properties_torq' + .webhook: >- + #/components/schemas/Connectors_connector_response_properties_webhook + .xmatters: >- + #/components/schemas/Connectors_connector_response_properties_xmatters + Connectors_update_connector_request_bedrock: + title: Update Amazon Bedrock connector request + type: object + required: + - config + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_bedrock' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_bedrock' + Connectors_update_connector_request_gemini: + title: Update Google Gemini connector request + type: object + required: + - config + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_gemini' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_gemini' + Connectors_update_connector_request_cases_webhook: + title: Update Webhook - Case Managment connector request + type: object + required: + - config + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_cases_webhook' + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_cases_webhook' + Connectors_update_connector_request_d3security: + title: Update D3 Security connector request + type: object + required: + - config + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_d3security' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_d3security' + Connectors_update_connector_request_email: + title: Update email connector request + type: object + required: + - config + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_email' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_email' + Connectors_update_connector_request_index: + title: Update index connector request + type: object + required: + - config + - name + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_index' + name: + type: string + description: The display name for the connector. + Connectors_update_connector_request_jira: + title: Update Jira connector request + type: object + required: + - config + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_jira' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_jira' + Connectors_update_connector_request_opsgenie: + title: Update Opsgenie connector request + type: object + required: + - config + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_opsgenie' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_opsgenie' + Connectors_update_connector_request_pagerduty: + title: Update PagerDuty connector request + type: object + required: + - config + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_pagerduty' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_pagerduty' + Connectors_update_connector_request_resilient: + title: Update IBM Resilient connector request + type: object + required: + - config + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_resilient' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_resilient' + Connectors_update_connector_request_sentinelone: + title: Update SentinelOne connector request + type: object + required: + - config + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_sentinelone' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_sentinelone' + Connectors_update_connector_request_serverlog: + title: Update server log connector request + type: object + required: + - name + properties: + name: + type: string + description: The display name for the connector. + Connectors_update_connector_request_servicenow: + title: Update ServiceNow ITSM connector or ServiceNow SecOps request + type: object + required: + - config + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_servicenow' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_servicenow' + Connectors_update_connector_request_servicenow_itom: + title: Create ServiceNow ITOM connector request + type: object + required: + - config + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_servicenow_itom' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_servicenow' + Connectors_update_connector_request_slack_api: + title: Update Slack connector request + type: object + required: + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_slack_api' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_slack_api' + Connectors_update_connector_request_slack_webhook: + title: Update Slack connector request + type: object + required: + - name + - secrets + properties: + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_slack_webhook' + Connectors_update_connector_request_swimlane: + title: Update Swimlane connector request + type: object + required: + - config + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_swimlane' + name: + type: string + description: The display name for the connector. + example: my-connector + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_swimlane' + Connectors_update_connector_request_teams: + title: Update Microsoft Teams connector request + type: object + required: + - name + - secrets + properties: + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_teams' + Connectors_update_connector_request_tines: + title: Update Tines connector request + type: object + required: + - config + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_tines' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_tines' + Connectors_update_connector_request_torq: + title: Update Torq connector request + type: object + required: + - config + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_torq' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_torq' + Connectors_update_connector_request_webhook: + title: Update Webhook connector request + type: object + required: + - config + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_webhook' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_webhook' + Connectors_update_connector_request_xmatters: + title: Update xMatters connector request + type: object + required: + - config + - name + - secrets + properties: + config: + $ref: '#/components/schemas/Connectors_config_properties_xmatters' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/Connectors_secrets_properties_xmatters' + Connectors_update_connector_request: + title: Update connector request body properties + description: The properties vary depending on the connector type. + oneOf: + - $ref: '#/components/schemas/Connectors_update_connector_request_bedrock' + - $ref: '#/components/schemas/Connectors_update_connector_request_gemini' + - $ref: >- + #/components/schemas/Connectors_update_connector_request_cases_webhook + - $ref: '#/components/schemas/Connectors_update_connector_request_d3security' + - $ref: '#/components/schemas/Connectors_update_connector_request_email' + - $ref: '#/components/schemas/Connectors_create_connector_request_genai' + - $ref: '#/components/schemas/Connectors_update_connector_request_index' + - $ref: '#/components/schemas/Connectors_update_connector_request_jira' + - $ref: '#/components/schemas/Connectors_update_connector_request_opsgenie' + - $ref: '#/components/schemas/Connectors_update_connector_request_pagerduty' + - $ref: '#/components/schemas/Connectors_update_connector_request_resilient' + - $ref: '#/components/schemas/Connectors_update_connector_request_sentinelone' + - $ref: '#/components/schemas/Connectors_update_connector_request_serverlog' + - $ref: '#/components/schemas/Connectors_update_connector_request_servicenow' + - $ref: >- + #/components/schemas/Connectors_update_connector_request_servicenow_itom + - $ref: '#/components/schemas/Connectors_update_connector_request_slack_api' + - $ref: >- + #/components/schemas/Connectors_update_connector_request_slack_webhook + - $ref: '#/components/schemas/Connectors_update_connector_request_swimlane' + - $ref: '#/components/schemas/Connectors_update_connector_request_teams' + - $ref: '#/components/schemas/Connectors_update_connector_request_tines' + - $ref: '#/components/schemas/Connectors_update_connector_request_torq' + - $ref: '#/components/schemas/Connectors_update_connector_request_webhook' + - $ref: '#/components/schemas/Connectors_update_connector_request_xmatters' + Connectors_features: + type: string + description: | + The feature that uses the connector. + enum: + - alerting + - cases + - generativeAIForSecurity + - generativeAIForObservability + - generativeAIForSearchPlayground + - siem + - uptime + Connectors_connector_types: + title: Connector types + type: string + description: >- + The type of connector. For example, `.email`, `.index`, `.jira`, + `.opsgenie`, or `.server-log`. + enum: + - .bedrock + - .gemini + - .cases-webhook + - .d3security + - .email + - .gen-ai + - .index + - .jira + - .opsgenie + - .pagerduty + - .resilient + - .sentinelone + - .servicenow + - .servicenow-itom + - .servicenow-sir + - .server-log + - .slack + - .slack_api + - .swimlane + - .teams + - .tines + - .torq + - .webhook + - .xmatters + example: .server-log + Connectors_run_connector_params_acknowledge_resolve_pagerduty: + title: PagerDuty connector parameters + description: Test an action that acknowledges or resolves a PagerDuty alert. + type: object + required: + - dedupKey + - eventAction + properties: + dedupKey: + description: The deduplication key for the PagerDuty alert. + type: string + maxLength: 255 + eventAction: + description: The type of event. + type: string + enum: + - acknowledge + - resolve + Connectors_run_connector_params_documents: + title: Index connector parameters + description: Test an action that indexes a document into Elasticsearch. + type: object + required: + - documents + properties: + documents: + type: array + description: The documents in JSON format for index connectors. + items: + type: object + additionalProperties: true + Connectors_run_connector_params_message_email: + title: Email connector parameters + description: > + Test an action that sends an email message. There must be at least one + recipient in `to`, `cc`, or `bcc`. + type: object + anyOf: + - required: + - bcc + - message + - subject + - required: + - cc + - message + - subject + - required: + - to + - message + - subject + properties: + bcc: + type: array + items: + type: string + description: > + A list of "blind carbon copy" email addresses. Addresses can be + specified in `user@host-name` format or in name `` + format + cc: + type: array + items: + type: string + description: > + A list of "carbon copy" email addresses. Addresses can be specified + in `user@host-name` format or in name `` format + message: + type: string + description: The email message text. Markdown format is supported. + subject: + type: string + description: The subject line of the email. + to: + type: array + description: > + A list of email addresses. Addresses can be specified in + `user@host-name` format or in name `` format. + items: + type: string + Connectors_run_connector_params_message_serverlog: + title: Server log connector parameters + description: Test an action that writes an entry to the Kibana server log. + type: object + required: + - message + properties: + level: + type: string + description: The log level of the message for server log connectors. + enum: + - debug + - error + - fatal + - info + - trace + - warn + default: info + message: + type: string + description: The message for server log connectors. + Connectors_run_connector_params_message_slack: + title: Slack connector parameters + description: > + Test an action that sends a message to Slack. It is applicable only when + the connector type is `.slack`. + type: object + required: + - message + properties: + message: + type: string + description: >- + The Slack message text, which cannot contain Markdown, images, or + other advanced formatting. + Connectors_run_connector_params_trigger_pagerduty: + title: PagerDuty connector parameters + description: Test an action that triggers a PagerDuty alert. + type: object + required: + - eventAction + properties: + class: + description: The class or type of the event. + type: string + example: cpu load + component: + description: >- + The component of the source machine that is responsible for the + event. + type: string + example: eth0 + customDetails: + description: Additional details to add to the event. + type: object + dedupKey: + description: > + All actions sharing this key will be associated with the same + PagerDuty alert. This value is used to correlate trigger and + resolution. + type: string + maxLength: 255 + eventAction: + description: The type of event. + type: string + enum: + - trigger + group: + description: The logical grouping of components of a service. + type: string + example: app-stack + links: + description: A list of links to add to the event. + type: array + items: + type: object + properties: + href: + description: The URL for the link. + type: string + text: + description: A plain text description of the purpose of the link. + type: string + severity: + description: The severity of the event on the affected system. + type: string + enum: + - critical + - error + - info + - warning + default: info + source: + description: > + The affected system, such as a hostname or fully qualified domain + name. Defaults to the Kibana saved object id of the action. + type: string + summary: + description: A summery of the event. + type: string + maxLength: 1024 + timestamp: + description: >- + An ISO-8601 timestamp that indicates when the event was detected or + generated. + type: string + format: date-time + Connectors_run_connector_subaction_addevent: + title: The addEvent subaction + type: object + required: + - subAction + description: The `addEvent` subaction for ServiceNow ITOM connectors. + properties: + subAction: + type: string + description: The action to test. + enum: + - addEvent + subActionParams: + type: object + description: The set of configuration properties for the action. + properties: + additional_info: + type: string + description: Additional information about the event. + description: + type: string + description: The details about the event. + event_class: + type: string + description: A specific instance of the source. + message_key: + type: string + description: >- + All actions sharing this key are associated with the same + ServiceNow alert. The default value is `:`. + metric_name: + type: string + description: The name of the metric. + node: + type: string + description: The host that the event was triggered for. + resource: + type: string + description: The name of the resource. + severity: + type: string + description: The severity of the event. + source: + type: string + description: The name of the event source type. + time_of_event: + type: string + description: The time of the event. + type: + type: string + description: The type of event. + Connectors_run_connector_subaction_closealert: + title: The closeAlert subaction + type: object + required: + - subAction + - subActionParams + description: The `closeAlert` subaction for Opsgenie connectors. + properties: + subAction: + type: string + description: The action to test. + enum: + - closeAlert + subActionParams: + type: object + required: + - alias + properties: + alias: + type: string + description: >- + The unique identifier used for alert deduplication in Opsgenie. + The alias must match the value used when creating the alert. + note: + type: string + description: Additional information for the alert. + source: + type: string + description: The display name for the source of the alert. + user: + type: string + description: The display name for the owner. + Connectors_run_connector_subaction_closeincident: + title: The closeIncident subaction + type: object + required: + - subAction + - subActionParams + description: The `closeIncident` subaction for ServiceNow ITSM connectors. + properties: + subAction: + type: string + description: The action to test. + enum: + - closeIncident + subActionParams: + type: object + required: + - incident + properties: + incident: + type: object + anyOf: + - required: + - correlation_id + - required: + - externalId + properties: + correlation_id: + type: string + nullable: true + description: > + An identifier that is assigned to the incident when it is + created by the connector. NOTE: If you use the default value + and the rule generates multiple alerts that use the same + alert IDs, the latest open incident for this correlation ID + is closed unless you specify the external ID. + maxLength: 100 + default: '{{rule.id}}:{{alert.id}}' + externalId: + type: string + nullable: true + description: >- + The unique identifier (`incidentId`) for the incident in + ServiceNow. + Connectors_run_connector_subaction_createalert: + title: The createAlert subaction + type: object + required: + - subAction + - subActionParams + description: The `createAlert` subaction for Opsgenie connectors. + properties: + subAction: + type: string + description: The action to test. + enum: + - createAlert + subActionParams: + type: object + required: + - message + properties: + actions: + type: array + description: The custom actions available to the alert. + items: + type: string + alias: + type: string + description: The unique identifier used for alert deduplication in Opsgenie. + description: + type: string + description: >- + A description that provides detailed information about the + alert. + details: + type: object + description: The custom properties of the alert. + additionalProperties: true + example: + key1: value1 + key2: value2 + entity: + type: string + description: >- + The domain of the alert. For example, the application or server + name. + message: + type: string + description: The alert message. + note: + type: string + description: Additional information for the alert. + priority: + type: string + description: The priority level for the alert. + enum: + - P1 + - P2 + - P3 + - P4 + - P5 + responders: + type: array + description: > + The entities to receive notifications about the alert. If `type` + is `user`, either `id` or `username` is required. If `type` is + `team`, either `id` or `name` is required. + items: + type: object + properties: + id: + type: string + description: The identifier for the entity. + name: + type: string + description: The name of the entity. + type: + type: string + description: The type of responders, in this case `escalation`. + enum: + - escalation + - schedule + - team + - user + username: + type: string + description: A valid email address for the user. + source: + type: string + description: The display name for the source of the alert. + tags: + type: array + description: The tags for the alert. + items: + type: string + user: + type: string + description: The display name for the owner. + visibleTo: + type: array + description: >- + The teams and users that the alert will be visible to without + sending a notification. Only one of `id`, `name`, or `username` + is required. + items: + type: object + required: + - type + properties: + id: + type: string + description: The identifier for the entity. + name: + type: string + description: The name of the entity. + type: + type: string + description: Valid values are `team` and `user`. + enum: + - team + - user + username: + type: string + description: >- + The user name. This property is required only when the + `type` is `user`. + Connectors_run_connector_subaction_fieldsbyissuetype: + title: The fieldsByIssueType subaction + type: object + required: + - subAction + - subActionParams + description: The `fieldsByIssueType` subaction for Jira connectors. + properties: + subAction: + type: string + description: The action to test. + enum: + - fieldsByIssueType + subActionParams: + type: object + required: + - id + properties: + id: + type: string + description: The Jira issue type identifier. + example: 10024 + Connectors_run_connector_subaction_getchoices: + title: The getChoices subaction + type: object + required: + - subAction + - subActionParams + description: >- + The `getChoices` subaction for ServiceNow ITOM, ServiceNow ITSM, and + ServiceNow SecOps connectors. + properties: + subAction: + type: string + description: The action to test. + enum: + - getChoices + subActionParams: + type: object + description: The set of configuration properties for the action. + required: + - fields + properties: + fields: + type: array + description: An array of fields. + items: + type: string + Connectors_run_connector_subaction_getfields: + title: The getFields subaction + type: object + required: + - subAction + description: >- + The `getFields` subaction for Jira, ServiceNow ITSM, and ServiceNow + SecOps connectors. + properties: + subAction: + type: string + description: The action to test. + enum: + - getFields + Connectors_run_connector_subaction_getincident: + title: The getIncident subaction + type: object + description: >- + The `getIncident` subaction for Jira, ServiceNow ITSM, and ServiceNow + SecOps connectors. + required: + - subAction + - subActionParams + properties: + subAction: + type: string + description: The action to test. + enum: + - getIncident + subActionParams: + type: object + required: + - externalId + properties: + externalId: + type: string + description: >- + The Jira, ServiceNow ITSM, or ServiceNow SecOps issue + identifier. + example: 71778 + Connectors_run_connector_subaction_issue: + title: The issue subaction + type: object + required: + - subAction + description: The `issue` subaction for Jira connectors. + properties: + subAction: + type: string + description: The action to test. + enum: + - issue + subActionParams: + type: object + required: + - id + properties: + id: + type: string + description: The Jira issue identifier. + example: 71778 + Connectors_run_connector_subaction_issues: + title: The issues subaction + type: object + required: + - subAction + - subActionParams + description: The `issues` subaction for Jira connectors. + properties: + subAction: + type: string + description: The action to test. + enum: + - issues + subActionParams: + type: object + required: + - title + properties: + title: + type: string + description: The title of the Jira issue. + Connectors_run_connector_subaction_issuetypes: + title: The issueTypes subaction + type: object + required: + - subAction + description: The `issueTypes` subaction for Jira connectors. + properties: + subAction: + type: string + description: The action to test. + enum: + - issueTypes + Connectors_run_connector_subaction_pushtoservice: + title: The pushToService subaction + type: object + required: + - subAction + - subActionParams + description: >- + The `pushToService` subaction for Jira, ServiceNow ITSM, ServiceNow + SecOps, Swimlane, and Webhook - Case Management connectors. + properties: + subAction: + type: string + description: The action to test. + enum: + - pushToService + subActionParams: + type: object + description: The set of configuration properties for the action. + properties: + comments: + type: array + description: >- + Additional information that is sent to Jira, ServiceNow ITSM, + ServiceNow SecOps, or Swimlane. + items: + type: object + properties: + comment: + type: string + description: >- + A comment related to the incident. For example, describe + how to troubleshoot the issue. + commentId: + type: integer + description: A unique identifier for the comment. + incident: + type: object + description: >- + Information necessary to create or update a Jira, ServiceNow + ITSM, ServiveNow SecOps, or Swimlane incident. + properties: + alertId: + type: string + description: The alert identifier for Swimlane connectors. + caseId: + type: string + description: >- + The case identifier for the incident for Swimlane + connectors. + caseName: + type: string + description: The case name for the incident for Swimlane connectors. + category: + type: string + description: >- + The category of the incident for ServiceNow ITSM and + ServiceNow SecOps connectors. + correlation_display: + type: string + description: >- + A descriptive label of the alert for correlation purposes + for ServiceNow ITSM and ServiceNow SecOps connectors. + correlation_id: + type: string + description: > + The correlation identifier for the security incident for + ServiceNow ITSM and ServiveNow SecOps connectors. Connectors + using the same correlation ID are associated with the same + ServiceNow incident. This value determines whether a new + ServiceNow incident is created or an existing one is + updated. Modifying this value is optional; if not modified, + the rule ID and alert ID are combined as `{{ruleID}}:{{alert + ID}}` to form the correlation ID value in ServiceNow. The + maximum character length for this value is 100 characters. + NOTE: Using the default configuration of `{{ruleID}}:{{alert + ID}}` ensures that ServiceNow creates a separate incident + record for every generated alert that uses a unique alert + ID. If the rule generates multiple alerts that use the same + alert IDs, ServiceNow creates and continually updates a + single incident record for the alert. + description: + type: string + description: >- + The description of the incident for Jira, ServiceNow ITSM, + ServiceNow SecOps, Swimlane, and Webhook - Case Management + connectors. + dest_ip: + description: > + A list of destination IP addresses related to the security + incident for ServiceNow SecOps connectors. The IPs are added + as observables to the security incident. + oneOf: + - type: string + - type: array + items: + type: string + externalId: + type: string + description: > + The Jira, ServiceNow ITSM, or ServiceNow SecOps issue + identifier. If present, the incident is updated. Otherwise, + a new incident is created. + id: + type: string + description: >- + The external case identifier for Webhook - Case Management + connectors. + impact: + type: string + description: The impact of the incident for ServiceNow ITSM connectors. + issueType: + type: integer + description: >- + The type of incident for Jira connectors. For example, + 10006. To obtain the list of valid values, set `subAction` + to `issueTypes`. + labels: + type: array + items: + type: string + description: > + The labels for the incident for Jira connectors. NOTE: + Labels cannot contain spaces. + malware_hash: + description: >- + A list of malware hashes related to the security incident + for ServiceNow SecOps connectors. The hashes are added as + observables to the security incident. + oneOf: + - type: string + - type: array + items: + type: string + malware_url: + type: string + description: >- + A list of malware URLs related to the security incident for + ServiceNow SecOps connectors. The URLs are added as + observables to the security incident. + oneOf: + - type: string + - type: array + items: + type: string + otherFields: + type: object + additionalProperties: true + maxProperties: 20 + description: > + Custom field identifiers and their values for Jira + connectors. + parent: + type: string + description: >- + The ID or key of the parent issue for Jira connectors. + Applies only to `Sub-task` types of issues. + priority: + type: string + description: >- + The priority of the incident in Jira and ServiceNow SecOps + connectors. + ruleName: + type: string + description: The rule name for Swimlane connectors. + severity: + type: string + description: >- + The severity of the incident for ServiceNow ITSM and + Swimlane connectors. + short_description: + type: string + description: > + A short description of the incident for ServiceNow ITSM and + ServiceNow SecOps connectors. It is used for searching the + contents of the knowledge base. + source_ip: + description: >- + A list of source IP addresses related to the security + incident for ServiceNow SecOps connectors. The IPs are added + as observables to the security incident. + oneOf: + - type: string + - type: array + items: + type: string + status: + type: string + description: >- + The status of the incident for Webhook - Case Management + connectors. + subcategory: + type: string + description: >- + The subcategory of the incident for ServiceNow ITSM and + ServiceNow SecOps connectors. + summary: + type: string + description: A summary of the incident for Jira connectors. + tags: + type: array + items: + type: string + description: A list of tags for Webhook - Case Management connectors. + title: + type: string + description: > + A title for the incident for Jira and Webhook - Case + Management connectors. It is used for searching the contents + of the knowledge base. + urgency: + type: string + description: The urgency of the incident for ServiceNow ITSM connectors. + Connectors_run_connector_subaction_postmessage: + title: The postMessage subaction + type: object + description: > + Test an action that sends a message to Slack. It is applicable only when + the connector type is `.slack_api`. + required: + - subAction + - subActionParams + properties: + subAction: + type: string + description: The action to test. + enum: + - postMessage + subActionParams: + type: object + description: The set of configuration properties for the action. + properties: + channelIds: + type: array + maxItems: 1 + description: > + The Slack channel identifier, which must be one of the + `allowedChannels` in the connector configuration. + items: + type: string + channels: + type: array + deprecated: true + description: | + The name of a channel that your Slack app has access to. + maxItems: 1 + items: + type: string + text: + type: string + description: > + The Slack message text. If it is a Slack webhook connector, the + text cannot contain Markdown, images, or other advanced + formatting. If it is a Slack web API connector, it can contain + either plain text or block kit messages. + minLength: 1 + Connectors_run_connector_subaction_validchannelid: + title: The validChannelId subaction + type: object + description: > + Retrieves information about a valid Slack channel identifier. It is + applicable only when the connector type is `.slack_api`. + required: + - subAction + - subActionParams + properties: + subAction: + type: string + description: The action to test. + enum: + - validChannelId + subActionParams: + type: object + required: + - channelId + properties: + channelId: + type: string + description: The Slack channel identifier. + example: C123ABC456 + Connectors_run_connector_request: + title: Run connector request body properties + description: The properties vary depending on the connector type. + type: object + required: + - params + properties: + params: + oneOf: + - $ref: >- + #/components/schemas/Connectors_run_connector_params_acknowledge_resolve_pagerduty + - $ref: '#/components/schemas/Connectors_run_connector_params_documents' + - $ref: >- + #/components/schemas/Connectors_run_connector_params_message_email + - $ref: >- + #/components/schemas/Connectors_run_connector_params_message_serverlog + - $ref: >- + #/components/schemas/Connectors_run_connector_params_message_slack + - $ref: >- + #/components/schemas/Connectors_run_connector_params_trigger_pagerduty + - title: Subaction parameters + description: Test an action that involves a subaction. + oneOf: + - $ref: >- + #/components/schemas/Connectors_run_connector_subaction_addevent + - $ref: >- + #/components/schemas/Connectors_run_connector_subaction_closealert + - $ref: >- + #/components/schemas/Connectors_run_connector_subaction_closeincident + - $ref: >- + #/components/schemas/Connectors_run_connector_subaction_createalert + - $ref: >- + #/components/schemas/Connectors_run_connector_subaction_fieldsbyissuetype + - $ref: >- + #/components/schemas/Connectors_run_connector_subaction_getchoices + - $ref: >- + #/components/schemas/Connectors_run_connector_subaction_getfields + - $ref: >- + #/components/schemas/Connectors_run_connector_subaction_getincident + - $ref: >- + #/components/schemas/Connectors_run_connector_subaction_issue + - $ref: >- + #/components/schemas/Connectors_run_connector_subaction_issues + - $ref: >- + #/components/schemas/Connectors_run_connector_subaction_issuetypes + - $ref: >- + #/components/schemas/Connectors_run_connector_subaction_postmessage + - $ref: >- + #/components/schemas/Connectors_run_connector_subaction_pushtoservice + - $ref: >- + #/components/schemas/Connectors_run_connector_subaction_validchannelid + discriminator: + propertyName: subAction + mapping: + addEvent: >- + #/components/schemas/Connectors_run_connector_subaction_addevent + closeAlert: >- + #/components/schemas/Connectors_run_connector_subaction_closealert + closeIncident: >- + #/components/schemas/Connectors_run_connector_subaction_closeincident + createAlert: >- + #/components/schemas/Connectors_run_connector_subaction_createalert + fieldsByIssueType: >- + #/components/schemas/Connectors_run_connector_subaction_fieldsbyissuetype + getChoices: >- + #/components/schemas/Connectors_run_connector_subaction_getchoices + getFields: >- + #/components/schemas/Connectors_run_connector_subaction_getfields + getIncident: >- + #/components/schemas/Connectors_run_connector_subaction_getincident + issue: >- + #/components/schemas/Connectors_run_connector_subaction_issue + issues: >- + #/components/schemas/Connectors_run_connector_subaction_issues + issueTypes: >- + #/components/schemas/Connectors_run_connector_subaction_issuetypes + pushToService: >- + #/components/schemas/Connectors_run_connector_subaction_pushtoservice + Connectors_action_response_properties: + title: Action response properties + description: The properties vary depending on the action type. + type: object + properties: + actionTypeId: + type: string + config: + type: object + id: + type: string + isDeprecated: + type: boolean + description: Indicates whether the action type is deprecated. + isMissingSecrets: + type: boolean + description: Indicates whether secrets are missing for the action. + isPreconfigured: + type: boolean + description: Indicates whether it is a preconfigured action. + name: + type: string + Data_views_400_response: + title: Bad request + type: object + required: + - statusCode + - error + - message + properties: + statusCode: + type: number + example: 400 + error: + type: string + example: Bad Request + message: + type: string + Data_views_allownoindex: + type: boolean + description: Allows the data view saved object to exist before the data is available. + Data_views_fieldattrs: + type: object + description: A map of field attributes by field name. + properties: + count: + type: integer + description: Popularity count for the field. + customDescription: + type: string + description: Custom description for the field. + maxLength: 300 + customLabel: + type: string + description: Custom label for the field. + Data_views_fieldformats: + type: object + description: A map of field formats by field name. + Data_views_namespaces: + type: array + description: >- + An array of space identifiers for sharing the data view between multiple + spaces. + items: + type: string + default: default + Data_views_runtimefieldmap: + type: object + description: A map of runtime field definitions by field name. + Data_views_sourcefilters: + type: array + description: The array of field names you want to filter out in Discover. + items: + type: object + required: + - value + properties: + value: + type: string + Data_views_timefieldname: + type: string + description: The timestamp field name, which you use for time-based data views. + Data_views_title: + type: string + description: >- + Comma-separated list of data streams, indices, and aliases that you want + to search. Supports wildcards (`*`). + Data_views_type: + type: string + description: When set to `rollup`, identifies the rollup data views. + Data_views_typemeta: + type: object + description: >- + When you use rollup indices, contains the field list for the rollup data + view API endpoints. + Data_views_create_data_view_request_object: + title: Create data view request + type: object + required: + - data_view + properties: + data_view: + type: object + required: + - title + description: The data view object. + properties: + allowNoIndex: + $ref: '#/components/schemas/Data_views_allownoindex' + fieldAttrs: + type: object + additionalProperties: + $ref: '#/components/schemas/Data_views_fieldattrs' + fieldFormats: + $ref: '#/components/schemas/Data_views_fieldformats' + fields: + type: object + id: + type: string + name: + type: string + description: The data view name. + namespaces: + $ref: '#/components/schemas/Data_views_namespaces' + runtimeFieldMap: + $ref: '#/components/schemas/Data_views_runtimefieldmap' + sourceFilters: + $ref: '#/components/schemas/Data_views_sourcefilters' + timeFieldName: + $ref: '#/components/schemas/Data_views_timefieldname' + title: + $ref: '#/components/schemas/Data_views_title' + type: + $ref: '#/components/schemas/Data_views_type' + typeMeta: + $ref: '#/components/schemas/Data_views_typemeta' + version: + type: string + override: + type: boolean + description: >- + Override an existing data view if a data view with the provided + title already exists. + default: false + Data_views_data_view_response_object: + title: Data view response properties + type: object + properties: + data_view: + type: object + properties: + allowNoIndex: + $ref: '#/components/schemas/Data_views_allownoindex' + fieldAttrs: + type: object + additionalProperties: + $ref: '#/components/schemas/Data_views_fieldattrs' + fieldFormats: + $ref: '#/components/schemas/Data_views_fieldformats' + fields: + type: object + id: + type: string + example: ff959d40-b880-11e8-a6d9-e546fe2bba5f + name: + type: string + description: The data view name. + namespaces: + $ref: '#/components/schemas/Data_views_namespaces' + runtimeFieldMap: + $ref: '#/components/schemas/Data_views_runtimefieldmap' + sourceFilters: + $ref: '#/components/schemas/Data_views_sourcefilters' + timeFieldName: + $ref: '#/components/schemas/Data_views_timefieldname' + title: + $ref: '#/components/schemas/Data_views_title' + typeMeta: + $ref: '#/components/schemas/Data_views_typemeta' + version: + type: string + example: WzQ2LDJd + Data_views_404_response: + type: object + properties: + error: + type: string + example: Not Found + enum: + - Not Found + message: + type: string + example: >- + Saved object [index-pattern/caaad6d0-920c-11ed-b36a-874bd1548a00] + not found + statusCode: + type: integer + example: 404 + enum: + - 404 + Data_views_update_data_view_request_object: + title: Update data view request + type: object + required: + - data_view + properties: + data_view: + type: object + description: > + The data view properties you want to update. Only the specified + properties are updated in the data view. Unspecified fields stay as + they are persisted. + properties: + allowNoIndex: + $ref: '#/components/schemas/Data_views_allownoindex' + fieldFormats: + $ref: '#/components/schemas/Data_views_fieldformats' + fields: + type: object + name: + type: string + runtimeFieldMap: + $ref: '#/components/schemas/Data_views_runtimefieldmap' + sourceFilters: + $ref: '#/components/schemas/Data_views_sourcefilters' + timeFieldName: + $ref: '#/components/schemas/Data_views_timefieldname' + title: + $ref: '#/components/schemas/Data_views_title' + type: + $ref: '#/components/schemas/Data_views_type' + typeMeta: + $ref: '#/components/schemas/Data_views_typemeta' + refresh_fields: + type: boolean + description: Reloads the data view fields after the data view is updated. + default: false + Machine_learning_APIs_mlSyncResponseSuccess: + type: boolean + description: The success or failure of the synchronization. + Machine_learning_APIs_mlSyncResponseAnomalyDetectors: + type: object + title: Sync API response for anomaly detection jobs + description: >- + The sync machine learning saved objects API response contains this + object when there are anomaly detection jobs affected by the + synchronization. There is an object for each relevant job, which + contains the synchronization status. + properties: + success: + $ref: '#/components/schemas/Machine_learning_APIs_mlSyncResponseSuccess' + Machine_learning_APIs_mlSyncResponseDatafeeds: + type: object + title: Sync API response for datafeeds + description: >- + The sync machine learning saved objects API response contains this + object when there are datafeeds affected by the synchronization. There + is an object for each relevant datafeed, which contains the + synchronization status. + properties: + success: + $ref: '#/components/schemas/Machine_learning_APIs_mlSyncResponseSuccess' + Machine_learning_APIs_mlSyncResponseDataFrameAnalytics: + type: object + title: Sync API response for data frame analytics jobs + description: >- + The sync machine learning saved objects API response contains this + object when there are data frame analytics jobs affected by the + synchronization. There is an object for each relevant job, which + contains the synchronization status. + properties: + success: + $ref: '#/components/schemas/Machine_learning_APIs_mlSyncResponseSuccess' + Machine_learning_APIs_mlSyncResponseSavedObjectsCreated: + type: object + title: Sync API response for created saved objects + description: >- + If saved objects are missing for machine learning jobs or trained + models, they are created when you run the sync machine learning saved + objects API. + properties: + anomaly-detector: + type: object + description: >- + If saved objects are missing for anomaly detection jobs, they are + created. + additionalProperties: + $ref: >- + #/components/schemas/Machine_learning_APIs_mlSyncResponseAnomalyDetectors + data-frame-analytics: + type: object + description: >- + If saved objects are missing for data frame analytics jobs, they are + created. + additionalProperties: + $ref: >- + #/components/schemas/Machine_learning_APIs_mlSyncResponseDataFrameAnalytics + trained-model: + type: object + description: If saved objects are missing for trained models, they are created. + additionalProperties: + $ref: >- + #/components/schemas/Machine_learning_APIs_mlSyncResponseTrainedModels + Machine_learning_APIs_mlSyncResponseSavedObjectsDeleted: + type: object + title: Sync API response for deleted saved objects + description: >- + If saved objects exist for machine learning jobs or trained models that + no longer exist, they are deleted when you run the sync machine learning + saved objects API. + properties: + anomaly-detector: + type: object + description: >- + If there are saved objects exist for nonexistent anomaly detection + jobs, they are deleted. + additionalProperties: + $ref: >- + #/components/schemas/Machine_learning_APIs_mlSyncResponseAnomalyDetectors + data-frame-analytics: + type: object + description: >- + If there are saved objects exist for nonexistent data frame + analytics jobs, they are deleted. + additionalProperties: + $ref: >- + #/components/schemas/Machine_learning_APIs_mlSyncResponseDataFrameAnalytics + trained-model: + type: object + description: >- + If there are saved objects exist for nonexistent trained models, + they are deleted. + additionalProperties: + $ref: >- + #/components/schemas/Machine_learning_APIs_mlSyncResponseTrainedModels + Machine_learning_APIs_mlSyncResponseTrainedModels: + type: object + title: Sync API response for trained models + description: >- + The sync machine learning saved objects API response contains this + object when there are trained models affected by the synchronization. + There is an object for each relevant trained model, which contains the + synchronization status. + properties: + success: + $ref: '#/components/schemas/Machine_learning_APIs_mlSyncResponseSuccess' + Machine_learning_APIs_mlSync200Response: + type: object + title: Successful sync API response + properties: + datafeedsAdded: + type: object + description: >- + If a saved object for an anomaly detection job is missing a datafeed + identifier, it is added when you run the sync machine learning saved + objects API. + additionalProperties: + $ref: '#/components/schemas/Machine_learning_APIs_mlSyncResponseDatafeeds' + datafeedsRemoved: + type: object + description: >- + If a saved object for an anomaly detection job references a datafeed + that no longer exists, it is deleted when you run the sync machine + learning saved objects API. + additionalProperties: + $ref: '#/components/schemas/Machine_learning_APIs_mlSyncResponseDatafeeds' + savedObjectsCreated: + $ref: >- + #/components/schemas/Machine_learning_APIs_mlSyncResponseSavedObjectsCreated + savedObjectsDeleted: + $ref: >- + #/components/schemas/Machine_learning_APIs_mlSyncResponseSavedObjectsDeleted + Machine_learning_APIs_mlSync4xxResponse: + type: object + title: Unsuccessful sync API response + properties: + error: + type: string + example: Unauthorized + message: + type: string + statusCode: + type: integer + example: 401 + Saved_objects_400_response: + title: Bad request + type: object + required: + - error + - message + - statusCode + properties: + error: + type: string + enum: + - Bad Request + message: + type: string + statusCode: + type: integer + enum: + - 400 + Saved_objects_attributes: + type: object + description: > + The data that you want to create. WARNING: When you create saved + objects, attributes are not validated, which allows you to pass + arbitrary and ill-formed data into the API that can break Kibana. Make + sure any data that you send to the API is properly formed. + Saved_objects_initial_namespaces: + type: array + description: > + Identifiers for the spaces in which this object is created. If this is + provided, the object is created only in the explicitly defined spaces. + If this is not provided, the object is created in the current space + (default behavior). For shareable object types (registered with + `namespaceType: 'multiple'`), this option can be used to specify one or + more spaces, including the "All spaces" identifier ('*'). For isolated + object types (registered with `namespaceType: 'single'` or + `namespaceType: 'multiple-isolated'`), this option can only be used to + specify a single space, and the "All spaces" identifier ('*') is not + allowed. For global object types (`registered with `namespaceType: + agnostic`), this option cannot be used. + Saved_objects_references: + type: array + description: > + Objects with `name`, `id`, and `type` properties that describe the other + saved objects that this object references. Use `name` in attributes to + refer to the other saved object, but never the `id`, which can update + automatically during migrations or import and export. + SLOs_indicator_properties_apm_availability: + title: APM availability + required: + - type + - params + description: Defines properties for the APM availability indicator type + type: object + properties: + params: + description: An object containing the indicator parameters. + type: object + nullable: false + required: + - service + - environment + - transactionType + - transactionName + - index + properties: + service: + description: The APM service name + type: string + example: o11y-app + environment: + description: The APM service environment or "*" + type: string + example: production + transactionType: + description: The APM transaction type or "*" + type: string + example: request + transactionName: + description: The APM transaction name or "*" + type: string + example: GET /my/api + filter: + description: KQL query used for filtering the data + type: string + example: 'service.foo : "bar"' + index: + description: The index used by APM metrics + type: string + example: metrics-apm*,apm* + type: + description: The type of indicator. + type: string + example: sli.apm.transactionDuration + SLOs_filter_meta: + title: FilterMeta + description: Defines properties for a filter + type: object + properties: + alias: + type: string + nullable: true + disabled: + type: boolean + negate: + type: boolean + controlledBy: + type: string + group: + type: string + index: + type: string + isMultiIndex: + type: boolean + type: + type: string + key: + type: string + params: + type: object + value: + type: string + field: + type: string + SLOs_filter: + title: Filter + description: Defines properties for a filter + type: object + properties: + query: + type: object + meta: + $ref: '#/components/schemas/SLOs_filter_meta' + SLOs_kql_with_filters: + title: KQL with filters + description: Defines properties for a filter + oneOf: + - description: the KQL query to filter the documents with. + type: string + example: 'field.environment : "production" and service.name : "my-service"' + - type: object + properties: + kqlQuery: + type: string + filters: + type: array + items: + $ref: '#/components/schemas/SLOs_filter' + SLOs_kql_with_filters_good: + title: KQL query for good events + description: The KQL query used to define the good events. + oneOf: + - description: the KQL query to filter the documents with. + type: string + example: 'request.latency <= 150 and request.status_code : "2xx"' + - type: object + properties: + kqlQuery: + type: string + filters: + type: array + items: + $ref: '#/components/schemas/SLOs_filter' + SLOs_kql_with_filters_total: + title: KQL query for all events + description: The KQL query used to define all events. + oneOf: + - description: the KQL query to filter the documents with. + type: string + example: 'field.environment : "production" and service.name : "my-service"' + - type: object + properties: + kqlQuery: + type: string + filters: + type: array + items: + $ref: '#/components/schemas/SLOs_filter' + SLOs_indicator_properties_custom_kql: + title: Custom Query + required: + - type + - params + description: Defines properties for a custom query indicator type + type: object + properties: + params: + description: An object containing the indicator parameters. + type: object + nullable: false + required: + - index + - timestampField + - good + - total + properties: + index: + description: The index or index pattern to use + type: string + example: my-service-* + dataViewId: + description: >- + The kibana data view id to use, primarily used to include data + view runtime mappings. Make sure to save SLO again if you + add/update run time fields to the data view and if those fields + are being used in slo queries. + type: string + example: 03b80ab3-003d-498b-881c-3beedbaf1162 + filter: + $ref: '#/components/schemas/SLOs_kql_with_filters' + good: + $ref: '#/components/schemas/SLOs_kql_with_filters_good' + total: + $ref: '#/components/schemas/SLOs_kql_with_filters_total' + timestampField: + description: | + The timestamp field used in the source indice. + type: string + example: timestamp + type: + description: The type of indicator. + type: string + example: sli.kql.custom + SLOs_indicator_properties_apm_latency: + title: APM latency + required: + - type + - params + description: Defines properties for the APM latency indicator type + type: object + properties: + params: + description: An object containing the indicator parameters. + type: object + nullable: false + required: + - service + - environment + - transactionType + - transactionName + - index + - threshold + properties: + service: + description: The APM service name + type: string + example: o11y-app + environment: + description: The APM service environment or "*" + type: string + example: production + transactionType: + description: The APM transaction type or "*" + type: string + example: request + transactionName: + description: The APM transaction name or "*" + type: string + example: GET /my/api + filter: + description: KQL query used for filtering the data + type: string + example: 'service.foo : "bar"' + index: + description: The index used by APM metrics + type: string + example: metrics-apm*,apm* + threshold: + description: The latency threshold in milliseconds + type: number + example: 250 + type: + description: The type of indicator. + type: string + example: sli.apm.transactionDuration + SLOs_indicator_properties_custom_metric: + title: Custom metric + required: + - type + - params + description: Defines properties for a custom metric indicator type + type: object + properties: + params: + description: An object containing the indicator parameters. + type: object + nullable: false + required: + - index + - timestampField + - good + - total + properties: + index: + description: The index or index pattern to use + type: string + example: my-service-* + dataViewId: + description: >- + The kibana data view id to use, primarily used to include data + view runtime mappings. Make sure to save SLO again if you + add/update run time fields to the data view and if those fields + are being used in slo queries. + type: string + example: 03b80ab3-003d-498b-881c-3beedbaf1162 + filter: + description: the KQL query to filter the documents with. + type: string + example: 'field.environment : "production" and service.name : "my-service"' + timestampField: + description: | + The timestamp field used in the source indice. + type: string + example: timestamp + good: + description: | + An object defining the "good" metrics and equation + type: object + required: + - metrics + - equation + properties: + metrics: + description: >- + List of metrics with their name, aggregation type, and + field. + type: array + items: + type: object + required: + - name + - aggregation + - field + properties: + name: + description: The name of the metric. Only valid options are A-Z + type: string + example: A + pattern: ^[A-Z]$ + aggregation: + description: >- + The aggregation type of the metric. Only valid option + is "sum" + type: string + example: sum + enum: + - sum + field: + description: The field of the metric. + type: string + example: processor.processed + filter: + description: The filter to apply to the metric. + type: string + example: 'processor.outcome: "success"' + equation: + description: The equation to calculate the "good" metric. + type: string + example: A + total: + description: | + An object defining the "total" metrics and equation + type: object + required: + - metrics + - equation + properties: + metrics: + description: >- + List of metrics with their name, aggregation type, and + field. + type: array + items: + type: object + required: + - name + - aggregation + - field + properties: + name: + description: The name of the metric. Only valid options are A-Z + type: string + example: A + pattern: ^[A-Z]$ + aggregation: + description: >- + The aggregation type of the metric. Only valid option + is "sum" + type: string + example: sum + enum: + - sum + field: + description: The field of the metric. + type: string + example: processor.processed + filter: + description: The filter to apply to the metric. + type: string + example: 'processor.outcome: *' + equation: + description: The equation to calculate the "total" metric. + type: string + example: A + type: + description: The type of indicator. + type: string + example: sli.metric.custom + SLOs_indicator_properties_histogram: + title: Histogram indicator + required: + - type + - params + description: Defines properties for a histogram indicator type + type: object + properties: + params: + description: An object containing the indicator parameters. + type: object + nullable: false + required: + - index + - timestampField + - good + - total + properties: + index: + description: The index or index pattern to use + type: string + example: my-service-* + dataViewId: + description: >- + The kibana data view id to use, primarily used to include data + view runtime mappings. Make sure to save SLO again if you + add/update run time fields to the data view and if those fields + are being used in slo queries. + type: string + example: 03b80ab3-003d-498b-881c-3beedbaf1162 + filter: + description: the KQL query to filter the documents with. + type: string + example: 'field.environment : "production" and service.name : "my-service"' + timestampField: + description: | + The timestamp field used in the source indice. + type: string + example: timestamp + good: + description: | + An object defining the "good" events + type: object + required: + - aggregation + - field + properties: + field: + description: The field use to aggregate the good events. + type: string + example: processor.latency + aggregation: + description: The type of aggregation to use. + type: string + example: value_count + enum: + - value_count + - range + filter: + description: The filter for good events. + type: string + example: 'processor.outcome: "success"' + from: + description: >- + The starting value of the range. Only required for "range" + aggregations. + type: number + example: 0 + to: + description: >- + The ending value of the range. Only required for "range" + aggregations. + type: number + example: 100 + total: + description: | + An object defining the "total" events + type: object + required: + - aggregation + - field + properties: + field: + description: The field use to aggregate the good events. + type: string + example: processor.latency + aggregation: + description: The type of aggregation to use. + type: string + example: value_count + enum: + - value_count + - range + filter: + description: The filter for total events. + type: string + example: 'processor.outcome : *' + from: + description: >- + The starting value of the range. Only required for "range" + aggregations. + type: number + example: 0 + to: + description: >- + The ending value of the range. Only required for "range" + aggregations. + type: number + example: 100 + type: + description: The type of indicator. + type: string + example: sli.histogram.custom + SLOs_timeslice_metric_basic_metric_with_field: + title: Timeslice Metric Basic Metric with Field + required: + - name + - aggregation + - field + type: object + properties: + name: + description: The name of the metric. Only valid options are A-Z + type: string + example: A + pattern: ^[A-Z]$ + aggregation: + description: The aggregation type of the metric. + type: string + example: sum + enum: + - sum + - avg + - min + - max + - std_deviation + - last_value + - cardinality + field: + description: The field of the metric. + type: string + example: processor.processed + filter: + description: The filter to apply to the metric. + type: string + example: 'processor.outcome: "success"' + SLOs_timeslice_metric_percentile_metric: + title: Timeslice Metric Percentile Metric + required: + - name + - aggregation + - field + - percentile + type: object + properties: + name: + description: The name of the metric. Only valid options are A-Z + type: string + example: A + pattern: ^[A-Z]$ + aggregation: + description: >- + The aggregation type of the metric. Only valid option is + "percentile" + type: string + example: percentile + enum: + - percentile + field: + description: The field of the metric. + type: string + example: processor.processed + percentile: + description: The percentile value. + type: number + example: 95 + filter: + description: The filter to apply to the metric. + type: string + example: 'processor.outcome: "success"' + SLOs_timeslice_metric_doc_count_metric: + title: Timeslice Metric Doc Count Metric + required: + - name + - aggregation + type: object + properties: + name: + description: The name of the metric. Only valid options are A-Z + type: string + example: A + pattern: ^[A-Z]$ + aggregation: + description: The aggregation type of the metric. Only valid option is "doc_count" + type: string + example: doc_count + enum: + - doc_count + filter: + description: The filter to apply to the metric. + type: string + example: 'processor.outcome: "success"' + SLOs_indicator_properties_timeslice_metric: + title: Timeslice metric + required: + - type + - params + description: Defines properties for a timeslice metric indicator type + type: object + properties: + params: + description: An object containing the indicator parameters. + type: object + nullable: false + required: + - index + - timestampField + - metric + properties: + index: + description: The index or index pattern to use + type: string + example: my-service-* + dataViewId: + description: >- + The kibana data view id to use, primarily used to include data + view runtime mappings. Make sure to save SLO again if you + add/update run time fields to the data view and if those fields + are being used in slo queries. + type: string + example: 03b80ab3-003d-498b-881c-3beedbaf1162 + filter: + description: the KQL query to filter the documents with. + type: string + example: 'field.environment : "production" and service.name : "my-service"' + timestampField: + description: | + The timestamp field used in the source indice. + type: string + example: timestamp + metric: + description: > + An object defining the metrics, equation, and threshold to + determine if it's a good slice or not + type: object + required: + - metrics + - equation + - comparator + - threshold + properties: + metrics: + description: >- + List of metrics with their name, aggregation type, and + field. + type: array + items: + anyOf: + - $ref: >- + #/components/schemas/SLOs_timeslice_metric_basic_metric_with_field + - $ref: >- + #/components/schemas/SLOs_timeslice_metric_percentile_metric + - $ref: >- + #/components/schemas/SLOs_timeslice_metric_doc_count_metric + equation: + description: The equation to calculate the metric. + type: string + example: A + comparator: + description: >- + The comparator to use to compare the equation to the + threshold. + type: string + example: GT + enum: + - GT + - GTE + - LT + - LTE + threshold: + description: >- + The threshold used to determine if the metric is a good + slice or not. + type: number + example: 100 + type: + description: The type of indicator. + type: string + example: sli.metric.timeslice + SLOs_time_window: + title: Time window + required: + - duration + - type + description: Defines properties for the SLO time window + type: object + properties: + duration: + description: >- + the duration formatted as {duration}{unit}. Accepted values for + rolling: 7d, 30d, 90d. Accepted values for calendar aligned: 1w + (weekly) or 1M (monthly) + type: string + example: 30d + type: + description: >- + Indicates weither the time window is a rolling or a calendar aligned + time window. + type: string + example: rolling + enum: + - rolling + - calendarAligned + SLOs_budgeting_method: + title: Budgeting method + type: string + description: The budgeting method to use when computing the rollup data. + enum: + - occurrences + - timeslices + example: occurrences + SLOs_objective: + title: Objective + required: + - target + description: Defines properties for the SLO objective + type: object + properties: + target: + description: the target objective between 0 and 1 excluded + type: number + minimum: 0 + maximum: 100 + exclusiveMinimum: true + exclusiveMaximum: true + example: 0.99 + timesliceTarget: + description: >- + the target objective for each slice when using a timeslices + budgeting method + type: number + minimum: 0 + maximum: 100 + example: 0.995 + timesliceWindow: + description: >- + the duration of each slice when using a timeslices budgeting method, + as {duraton}{unit} + type: string + example: 5m + SLOs_settings: + title: Settings + description: Defines properties for SLO settings. + type: object + properties: + syncDelay: + description: The synch delay to apply to the transform. Default 1m + type: string + default: 1m + example: 5m + frequency: + description: Configure how often the transform runs, default 1m + type: string + default: 1m + example: 5m + preventInitialBackfill: + description: Prevents the transform from backfilling data when it starts. + type: boolean + default: false + example: true + SLOs_summary_status: + title: summary status + type: string + enum: + - NO_DATA + - HEALTHY + - DEGRADING + - VIOLATED + example: HEALTHY + SLOs_error_budget: + title: Error budget + type: object + required: + - initial + - consumed + - remaining + - isEstimated + properties: + initial: + type: number + description: The initial error budget, as 1 - objective + example: 0.02 + consumed: + type: number + description: The error budget consummed, as a percentage of the initial value. + example: 0.8 + remaining: + type: number + description: The error budget remaining, as a percentage of the initial value. + example: 0.2 + isEstimated: + type: boolean + description: >- + Only for SLO defined with occurrences budgeting method and calendar + aligned time window. + example: true + SLOs_summary: + title: Summary + type: object + description: The SLO computed data + required: + - status + - sliValue + - errorBudget + properties: + status: + $ref: '#/components/schemas/SLOs_summary_status' + sliValue: + type: number + example: 0.9836 + errorBudget: + $ref: '#/components/schemas/SLOs_error_budget' + SLOs_slo_with_summary_response: + title: SLO response + type: object + required: + - id + - name + - description + - indicator + - timeWindow + - budgetingMethod + - objective + - settings + - revision + - summary + - enabled + - groupBy + - instanceId + - tags + - createdAt + - updatedAt + - version + properties: + id: + description: The identifier of the SLO. + type: string + example: 8853df00-ae2e-11ed-90af-09bb6422b258 + name: + description: The name of the SLO. + type: string + example: My Service SLO + description: + description: The description of the SLO. + type: string + example: My SLO description + indicator: + discriminator: + propertyName: type + mapping: + sli.apm.transactionErrorRate: '#/components/schemas/SLOs_indicator_properties_apm_availability' + sli.kql.custom: '#/components/schemas/SLOs_indicator_properties_custom_kql' + sli.apm.transactionDuration: '#/components/schemas/SLOs_indicator_properties_apm_latency' + sli.metric.custom: '#/components/schemas/SLOs_indicator_properties_custom_metric' + sli.histogram.custom: '#/components/schemas/SLOs_indicator_properties_histogram' + sli.metric.timeslice: '#/components/schemas/SLOs_indicator_properties_timeslice_metric' + oneOf: + - $ref: '#/components/schemas/SLOs_indicator_properties_custom_kql' + - $ref: '#/components/schemas/SLOs_indicator_properties_apm_availability' + - $ref: '#/components/schemas/SLOs_indicator_properties_apm_latency' + - $ref: '#/components/schemas/SLOs_indicator_properties_custom_metric' + - $ref: '#/components/schemas/SLOs_indicator_properties_histogram' + - $ref: '#/components/schemas/SLOs_indicator_properties_timeslice_metric' + timeWindow: + $ref: '#/components/schemas/SLOs_time_window' + budgetingMethod: + $ref: '#/components/schemas/SLOs_budgeting_method' + objective: + $ref: '#/components/schemas/SLOs_objective' + settings: + $ref: '#/components/schemas/SLOs_settings' + revision: + description: The SLO revision + type: number + example: 2 + summary: + $ref: '#/components/schemas/SLOs_summary' + enabled: + description: Indicate if the SLO is enabled + type: boolean + example: true + groupBy: + description: optional group by field to use to generate an SLO per distinct value + type: string + example: some.field + instanceId: + description: the value derived from the groupBy field, if present, otherwise '*' + type: string + example: host-abcde + tags: + description: List of tags + type: array + items: + type: string + createdAt: + description: The creation date + type: string + example: '2023-01-12T10:03:19.000Z' + updatedAt: + description: The last update date + type: string + example: '2023-01-12T10:03:19.000Z' + version: + description: The internal SLO version + type: number + example: 2 + SLOs_find_slo_response: + title: Find SLO response + description: | + A paginated response of SLOs matching the query. + type: object + properties: + page: + type: number + example: 1 + perPage: + type: number + example: 25 + total: + type: number + example: 34 + results: + type: array + items: + $ref: '#/components/schemas/SLOs_slo_with_summary_response' + SLOs_400_response: + title: Bad request + type: object + required: + - statusCode + - error + - message + properties: + statusCode: + type: number + example: 400 + error: + type: string + example: Bad Request + message: + type: string + example: 'Invalid value ''foo'' supplied to: [...]' + SLOs_401_response: + title: Unauthorized + type: object + required: + - statusCode + - error + - message + properties: + statusCode: + type: number + example: 401 + error: + type: string + example: Unauthorized + message: + type: string + example: "[security_exception\n\tRoot causes:\n\t\tsecurity_exception: unable to authenticate user [elastics] for REST request [/_security/_authenticate]]: unable to authenticate user [elastics] for REST request [/_security/_authenticate]" + SLOs_403_response: + title: Unauthorized + type: object + required: + - statusCode + - error + - message + properties: + statusCode: + type: number + example: 403 + error: + type: string + example: Unauthorized + message: + type: string + example: "[security_exception\n\tRoot causes:\n\t\tsecurity_exception: unable to authenticate user [elastics] for REST request [/_security/_authenticate]]: unable to authenticate user [elastics] for REST request [/_security/_authenticate]" + SLOs_404_response: + title: Not found + type: object + required: + - statusCode + - error + - message + properties: + statusCode: + type: number + example: 404 + error: + type: string + example: Not Found + message: + type: string + example: SLO [3749f390-03a3-11ee-8139-c7ff60a1692d] not found + SLOs_create_slo_request: + title: Create SLO request + description: > + The create SLO API request body varies depending on the type of + indicator, time window and budgeting method. + type: object + required: + - name + - description + - indicator + - timeWindow + - budgetingMethod + - objective + properties: + id: + description: >- + A optional and unique identifier for the SLO. Must be between 8 and + 36 chars + type: string + example: my-super-slo-id + name: + description: A name for the SLO. + type: string + description: + description: A description for the SLO. + type: string + indicator: + oneOf: + - $ref: '#/components/schemas/SLOs_indicator_properties_custom_kql' + - $ref: '#/components/schemas/SLOs_indicator_properties_apm_availability' + - $ref: '#/components/schemas/SLOs_indicator_properties_apm_latency' + - $ref: '#/components/schemas/SLOs_indicator_properties_custom_metric' + - $ref: '#/components/schemas/SLOs_indicator_properties_histogram' + - $ref: '#/components/schemas/SLOs_indicator_properties_timeslice_metric' + timeWindow: + $ref: '#/components/schemas/SLOs_time_window' + budgetingMethod: + $ref: '#/components/schemas/SLOs_budgeting_method' + objective: + $ref: '#/components/schemas/SLOs_objective' + settings: + $ref: '#/components/schemas/SLOs_settings' + groupBy: + description: optional group by field to use to generate an SLO per distinct value + type: string + example: some.field + tags: + description: List of tags + type: array + items: + type: string + SLOs_create_slo_response: + title: Create SLO response + type: object + required: + - id + properties: + id: + type: string + example: 8853df00-ae2e-11ed-90af-09bb6422b258 + SLOs_409_response: + title: Conflict + type: object + required: + - statusCode + - error + - message + properties: + statusCode: + type: number + example: 409 + error: + type: string + example: Conflict + message: + type: string + example: SLO [d077e940-1515-11ee-9c50-9d096392f520] already exists + SLOs_update_slo_request: + title: Update SLO request + description: > + The update SLO API request body varies depending on the type of + indicator, time window and budgeting method. Partial update is handled. + type: object + properties: + name: + description: A name for the SLO. + type: string + description: + description: A description for the SLO. + type: string + indicator: + oneOf: + - $ref: '#/components/schemas/SLOs_indicator_properties_custom_kql' + - $ref: '#/components/schemas/SLOs_indicator_properties_apm_availability' + - $ref: '#/components/schemas/SLOs_indicator_properties_apm_latency' + - $ref: '#/components/schemas/SLOs_indicator_properties_custom_metric' + - $ref: '#/components/schemas/SLOs_indicator_properties_histogram' + - $ref: '#/components/schemas/SLOs_indicator_properties_timeslice_metric' + timeWindow: + $ref: '#/components/schemas/SLOs_time_window' + budgetingMethod: + $ref: '#/components/schemas/SLOs_budgeting_method' + objective: + $ref: '#/components/schemas/SLOs_objective' + settings: + $ref: '#/components/schemas/SLOs_settings' + tags: + description: List of tags + type: array + items: + type: string + SLOs_slo_definition_response: + title: SLO definition response + type: object + required: + - id + - name + - description + - indicator + - timeWindow + - budgetingMethod + - objective + - settings + - revision + - enabled + - groupBy + - tags + - createdAt + - updatedAt + - version + properties: + id: + description: The identifier of the SLO. + type: string + example: 8853df00-ae2e-11ed-90af-09bb6422b258 + name: + description: The name of the SLO. + type: string + example: My Service SLO + description: + description: The description of the SLO. + type: string + example: My SLO description + indicator: + discriminator: + propertyName: type + mapping: + sli.apm.transactionErrorRate: '#/components/schemas/SLOs_indicator_properties_apm_availability' + sli.kql.custom: '#/components/schemas/SLOs_indicator_properties_custom_kql' + sli.apm.transactionDuration: '#/components/schemas/SLOs_indicator_properties_apm_latency' + sli.metric.custom: '#/components/schemas/SLOs_indicator_properties_custom_metric' + sli.histogram.custom: '#/components/schemas/SLOs_indicator_properties_histogram' + sli.metric.timeslice: '#/components/schemas/SLOs_indicator_properties_timeslice_metric' + oneOf: + - $ref: '#/components/schemas/SLOs_indicator_properties_custom_kql' + - $ref: '#/components/schemas/SLOs_indicator_properties_apm_availability' + - $ref: '#/components/schemas/SLOs_indicator_properties_apm_latency' + - $ref: '#/components/schemas/SLOs_indicator_properties_custom_metric' + - $ref: '#/components/schemas/SLOs_indicator_properties_histogram' + - $ref: '#/components/schemas/SLOs_indicator_properties_timeslice_metric' + timeWindow: + $ref: '#/components/schemas/SLOs_time_window' + budgetingMethod: + $ref: '#/components/schemas/SLOs_budgeting_method' + objective: + $ref: '#/components/schemas/SLOs_objective' + settings: + $ref: '#/components/schemas/SLOs_settings' + revision: + description: The SLO revision + type: number + example: 2 + enabled: + description: Indicate if the SLO is enabled + type: boolean + example: true + groupBy: + description: optional group by field to use to generate an SLO per distinct value + type: string + example: some.field + tags: + description: List of tags + type: array + items: + type: string + createdAt: + description: The creation date + type: string + example: '2023-01-12T10:03:19.000Z' + updatedAt: + description: The last update date + type: string + example: '2023-01-12T10:03:19.000Z' + version: + description: The internal SLO version + type: number + example: 2 + SLOs_historical_summary_request: + title: Historical summary request + type: object + required: + - list + properties: + list: + description: The list of SLO identifiers to get the historical summary for + type: array + items: + type: string + example: 8853df00-ae2e-11ed-90af-09bb6422b258 + SLOs_historical_summary_response: + title: Historical summary response + type: object + additionalProperties: + type: array + items: + type: object + properties: + date: + type: string + example: '2022-01-01T00:00:00.000Z' + status: + $ref: '#/components/schemas/SLOs_summary_status' + sliValue: + type: number + example: 0.9836 + errorBudget: + $ref: '#/components/schemas/SLOs_error_budget' + SLOs_find_slo_definitions_response: + title: Find SLO definitions response + description: | + A paginated response of SLO definitions matching the query. + type: object + properties: + page: + type: number + example: 2 + perPage: + type: number + example: 100 + total: + type: number + example: 123 + results: + type: array + items: + $ref: '#/components/schemas/SLOs_slo_definition_response' + SLOs_delete_slo_instances_request: + title: Delete SLO instances request + description: > + The delete SLO instances request takes a list of SLO id and instance id, + then delete the rollup and summary data. This API can be used to remove + the staled data of an instance SLO that no longer get updated. + type: object + required: + - list + properties: + list: + description: An array of slo id and instance id + type: array + items: + type: object + required: + - sloId + - instanceId + properties: + sloId: + description: The SLO unique identifier + type: string + example: 8853df00-ae2e-11ed-90af-09bb6422b258 + instanceId: + description: The SLO instance identifier + type: string + example: 8853df00-ae2e-11ed-90af-09bb6422b258 + examples: + Connectors_create_email_connector_request: + summary: Create an email connector. + value: + name: email-connector-1 + connector_type_id: .email + config: + from: tester@example.com + hasAuth: true + host: https://example.com + port: 1025 + secure: false + service: other + secrets: + user: username + password: password + Connectors_create_index_connector_request: + summary: Create an index connector. + value: + name: my-connector + connector_type_id: .index + config: + index: test-index + Connectors_create_webhook_connector_request: + summary: Create a webhook connector with SSL authentication. + value: + name: my-webhook-connector + connector_type_id: .webhook + config: + method: post + url: https://example.com + authType: webhook-authentication-ssl + certType: ssl-crt-key + secrets: + crt: QmFnIEF0dH... + key: LS0tLS1CRUdJ... + password: my-passphrase + Connectors_create_xmatters_connector_request: + summary: Create an xMatters connector with URL authentication. + value: + name: my-xmatters-connector + connector_type_id: .xmatters + config: + usesBasic: false + secrets: + secretsUrl: https://example.com?apiKey=xxxxx + Connectors_create_email_connector_response: + summary: A new email connector. + value: + id: 90a82c60-478f-11ee-a343-f98a117c727f + connector_type_id: .email + name: email-connector-1 + config: + from: tester@example.com + service: other + host: https://example.com + port: 1025 + secure: false + hasAuth: true + tenantId: null + clientId: null + oauthTokenUrl: null + is_preconfigured: false + is_deprecated: false + is_missing_secrets: false + is_system_action: false + Connectors_create_index_connector_response: + summary: A new index connector. + value: + id: c55b6eb0-6bad-11eb-9f3b-611eebc6c3ad + connector_type_id: .index + name: my-connector + config: + index: test-index + refresh: false + executionTimeField: null + is_preconfigured: false + is_deprecated: false + is_missing_secrets: false + is_system_action: false + Connectors_create_webhook_connector_response: + summary: A new webhook connector. + value: + id: 900eb010-3b9d-11ee-a642-8ffbb94e38bd + name: my-webhook-connector + config: + method: post + url: https://example.com + authType: webhook-authentication-ssl + certType: ssl-crt-key + verificationMode: full + headers: null + hasAuth: true + connector_type_id: .webhook + is_preconfigured: false + is_deprecated: false + is_missing_secrets: false + is_system_action: false + Connectors_create_xmatters_connector_response: + summary: A new xMatters connector. + value: + id: 4d2d8da0-4d1f-11ee-9367-577408be4681 + name: my-xmatters-connector + config: + usesBasic: false + configUrl: null + connector_type_id: .xmatters + is_preconfigured: false + is_deprecated: false + is_missing_secrets: false + is_system_action: false + Connectors_get_connector_response: + summary: Get connector details. + value: + id: df770e30-8b8b-11ed-a780-3b746c987a81 + name: my_server_log_connector + config: {} + connector_type_id: .server-log + is_preconfigured: false + is_deprecated: false + is_missing_secrets: false + is_system_action: false + Connectors_update_index_connector_request: + summary: Update an index connector. + value: + name: updated-connector + config: + index: updated-index + Connectors_get_connectors_response: + summary: A list of connectors + value: + - id: preconfigured-email-connector + name: my-preconfigured-email-notification + connector_type_id: .email + is_preconfigured: true + is_deprecated: false + referenced_by_count: 0 + is_system_action: false + - id: e07d0c80-8b8b-11ed-a780-3b746c987a81 + name: my-index-connector + config: + index: test-index + refresh: false + executionTimeField: null + connector_type_id: .index + is_preconfigured: false + is_deprecated: false + referenced_by_count: 2 + is_missing_secrets: false + is_system_action: false + Connectors_get_connector_types_response: + summary: A list of connector types + value: + - id: .swimlane + name: Swimlane + enabled: true + enabled_in_config: true + enabled_in_license: true + minimum_license_required: gold + supported_feature_ids: + - alerting + - cases + - siem + - id: .index + name: Index + enabled: true + enabled_in_config: true + enabled_in_license: true + minimum_license_required: basic + supported_feature_ids: + - alerting + - uptime + - siem + - id: .server-log + name: Server log + enabled: true + enabled_in_config: true + enabled_in_license: true + minimum_license_required: basic + supported_feature_ids: + - alerting + - uptime + Connectors_run_index_connector_request: + summary: Run an index connector. + value: + params: + documents: + - id: my_doc_id + name: my_doc_name + message: hello, world + Connectors_run_jira_connector_request: + summary: Run a Jira connector to retrieve the list of issue types. + value: + params: + subAction: issueTypes + Connectors_run_server_log_connector_request: + summary: Run a server log connector. + value: + params: + level: warn + message: Test warning message. + Connectors_run_servicenow_itom_connector_request: + summary: Run a ServiceNow ITOM connector to retrieve the list of choices. + value: + params: + subAction: getChoices + subActionParams: + fields: + - severity + - urgency + Connectors_run_slack_api_connector_request: + summary: >- + Run a Slack connector that uses the web API method to post a message on + a channel. + value: + params: + subAction: postMessage + subActionParams: + channelIds: + - C123ABC456 + text: A test message. + Connectors_run_swimlane_connector_request: + summary: Run a Swimlane connector to create an incident. + value: + params: + subAction: pushToService + subActionParams: + comments: + - commentId: 1 + comment: A comment about the incident. + incident: + caseId: '1000' + caseName: Case name + description: Description of the incident. + Connectors_run_index_connector_response: + summary: Response from running an index connector. + value: + connector_id: fd38c600-96a5-11ed-bb79-353b74189cba + data: + errors: false + items: + - create: + _id: 4JtvwYUBrcyxt2NnfW3y + _index: my-index + _primary_term: 1 + _seq_no: 0 + _shards: + failed: 0 + successful: 1 + total: 2 + _version: 1 + result: created + status: 201 + took: 135 + status: ok + Connectors_run_jira_connector_response: + summary: Response from retrieving the list of issue types for a Jira connector. + value: + connector_id: b3aad810-edbe-11ec-82d1-11348ecbf4a6 + data: + - id: 10024 + name: Improvement + - id: 10006 + name: Task + - id: 10007 + name: Sub-task + - id: 10025 + name: New Feature + - id: 10023 + name: Bug + - id: 10000 + name: Epic + status: ok + Connectors_run_server_log_connector_response: + summary: Response from running a server log connector. + value: + connector_id: 7fc7b9a0-ecc9-11ec-8736-e7d63118c907 + status: ok + Connectors_run_servicenow_itom_connector_response: + summary: >- + Response from retrieving the list of choices for a ServiceNow ITOM + connector. + value: + connector_id: 9d9be270-2fd2-11ed-b0e0-87533c532698 + data: + - dependent_value: '' + element: severity + label: Critical + value: 1 + - dependent_value: '' + element: severity + label: Major + value: 2 + - dependent_value: '' + element: severity + label: Minor + value: 3 + - dependent_value: '' + element: severity + label: Warning + value: 4 + - dependent_value: '' + element: severity + label: OK + value: 5 + - dependent_value: '' + element: severity + label: Clear + value: 0 + - dependent_value: '' + element: urgency + label: 1 - High + value: 1 + - dependent_value: '' + element: urgency + label: 2 - Medium + value: 2 + - dependent_value: '' + element: urgency + label: 3 - Low + value: 3 + status: ok + Connectors_run_slack_api_connector_response: + summary: Response from posting a message with a Slack connector. + value: + status: ok + data: + ok: true + channel: C123ABC456 + ts: '1234567890.123456' + message: + bot_id: B12BCDEFGHI + type: message + text: A test message + user: U12A345BC6D + ts: '1234567890.123456' + app_id: A01BC2D34EF + blocks: + - type: rich_text + block_id: /NXe + elements: + - type: rich_text_section + elements: + - type: text + text: A test message. + team: T01ABCDE2F + bot_profile: + id: B12BCDEFGHI + app_id: A01BC2D34EF + name: test + icons: + image_36: https://a.slack-edge.com/80588/img/plugins/app/bot_36.png + deleted: false + updated: 1672169705 + team_id: T01ABCDE2F + connector_id: .slack_api + Connectors_run_swimlane_connector_response: + summary: Response from creating a Swimlane incident. + value: + connector_id: a4746470-2f94-11ed-b0e0-87533c532698 + data: + id: aKPmBHWzmdRQtx6Mx + title: TEST-457 + url: >- + https://elastic.swimlane.url.us/record/aNcL2xniGHGpa2AHb/aKPmBHWzmdRQtx6Mx + pushedDate: '2022-09-08T16:52:27.866Z' + comments: + - commentId: 1 + pushedDate: '2022-09-08T16:52:27.865Z' + status: ok + Connectors_run_cases_webhook_connector_request: + summary: Run a Webhook - Case Management connector to create a case. + value: + params: + subAction: pushToService + subActionParams: + comments: + - commentId: 1 + comment: A comment about the incident. + incident: + title: Case title + description: Description of the incident. + tags: + - tag1 + - tag2 + severity: low + status: open + id: caseID + Connectors_run_email_connector_request: + summary: Send an email message from an email connector. + value: + params: + bcc: + - user1@example.com + cc: + - user2@example.com + - user3@example.com + message: Test email message. + subject: Test message subject + to: + - user4@example.com + Connectors_run_pagerduty_connector_request: + summary: Run a PagerDuty connector to trigger an alert. + value: + params: + eventAction: trigger + summary: A brief event summary + links: + - href: http://example.com/pagerduty + text: An example link + customDetails: + my_data_1: test data + Connectors_run_cases_webhook_connector_response: + summary: >- + Response from a pushToService action for a Webhook - Case Management + connector. + value: + connector_id: 1824b5b8-c005-4dcc-adac-57f92db46459 + data: + id: 100665 + title: TEST-29034 + url: https://example.com/browse/TEST-29034 + pushedDate: '2023-12-05T19:43:36.360Z' + comments: + - commentId: 1 + pushedDate: '2023-12-05T19:43:36.360Z' + status: ok + Connectors_run_email_connector_response: + summary: Response for sending a message from an email connector. + value: + connector_id: 7fc7b9a0-ecc9-11ec-8736-e7d63118c907 + data: + accepted: + - user1@example.com + - user2@example.com + - user3@example.com + - user4@example.com + envelope: + from: tester@example.com + to: + - user1@example.com + - user2@example.com + - user3@example.com + - user4@example.com + envelopeTime: 8 + messageTime: 3 + messageSize: 729 + response: 250 Message queued as QzEXKcGJ + messageId: <08a92d29-642a-0706-750c-de5996bd5cf3@example.com> + rejected: [] + status: ok + Connectors_run_pagerduty_connector_response: + summary: Response from running a PagerDuty connector. + value: + connector_id: 45de9f70-954f-4608-b12a-db7cf808e49d + data: + dedup_key: 5115e138b26b484a81eaea779faa6016 + message: Event processed + status: success + status: ok + Connectors_get_connector_types_generativeai_response: + summary: A list of connector types for the `generativeAI` feature. + value: + - id: .gen-ai + name: OpenAI + enabled: true + enabled_in_config: true + enabled_in_license: true + minimum_license_required: enterprise + supported_feature_ids: + - generativeAIForSecurity + - generativeAIForObservability + - generativeAIForSearchPlayground + is_system_action_type: false + - id: .bedrock + name: AWS Bedrock + enabled: true + enabled_in_config: true + enabled_in_license: true + minimum_license_required: enterprise + supported_feature_ids: + - generativeAIForSecurity + - generativeAIForObservability + - generativeAIForSearchPlayground + is_system_action_type: false + - id: .gemini + name: Google Gemini + enabled: true + enabled_in_config: true + enabled_in_license: true + minimum_license_required: enterprise + supported_feature_ids: + - generativeAIForSecurity + is_system_action_type: false + Data_views_get_data_views_response: + summary: The get all data views API returns a list of data views. + value: + data_view: + - id: ff959d40-b880-11e8-a6d9-e546fe2bba5f + namespaces: + - default + title: kibana_sample_data_ecommerce + typeMeta: {} + name: Kibana Sample Data eCommerce + - id: d3d7af60-4c81-11e8-b3d7-01146121b73d + namespaces: + - default + title: kibana_sample_data_flights + name: Kibana Sample Data Flights + - id: 90943e30-9a47-11e8-b64d-95841ca0b247 + namespaces: + - default + title: kibana_sample_data_logs + name: Kibana Sample Data Logs + Data_views_create_data_view_request: + summary: Create a data view with runtime fields. + value: + data_view: + title: logstash-* + name: My Logstash data view + runtimeFieldMap: + runtime_shape_name: + type: keyword + script: + source: emit(doc['shape_name'].value) + Data_views_get_data_view_response: + summary: >- + The get data view API returns a JSON object that contains information + about the data view. + value: + data_view: + id: ff959d40-b880-11e8-a6d9-e546fe2bba5f + version: WzUsMV0= + title: kibana_sample_data_ecommerce + timeFieldName: order_date + sourceFilters: [] + fields: + _id: + count: 0 + name: _id + type: string + esTypes: + - _id + scripted: false + searchable: true + aggregatable: false + readFromDocValues: false + format: + id: string + shortDotsEnable: false + isMapped: true + _index: + count: 0 + name: _index + type: string + esTypes: + - _index + scripted: false + searchable: true + aggregatable: true + readFromDocValues: false + format: + id: string + shortDotsEnable: false + isMapped: true + _score: + count: 0 + name: _score + type: number + scripted: false + searchable: false + aggregatable: false + readFromDocValues: false + format: + id: number + shortDotsEnable: false + isMapped: true + _source: + count: 0 + name: _source + type: _source + esTypes: + - _source + scripted: false + searchable: false + aggregatable: false + readFromDocValues: false + format: + id: _source + shortDotsEnable: false + isMapped: true + category: + count: 0 + name: category + type: string + esTypes: + - text + scripted: false + searchable: true + aggregatable: false + readFromDocValues: false + format: + id: string + shortDotsEnable: false + isMapped: true + category.keyword: + count: 0 + name: category.keyword + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + subType: + multi: + parent: category + format: + id: string + shortDotsEnable: false + isMapped: true + currency: + count: 0 + name: currency + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + customer_birth_date: + count: 0 + name: customer_birth_date + type: date + esTypes: + - date + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: date + shortDotsEnable: false + isMapped: true + customer_first_name: + count: 0 + name: customer_first_name + type: string + esTypes: + - text + scripted: false + searchable: true + aggregatable: false + readFromDocValues: false + format: + id: string + shortDotsEnable: false + isMapped: true + customer_first_name.keyword: + count: 0 + name: customer_first_name.keyword + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + subType: + multi: + parent: customer_first_name + format: + id: string + shortDotsEnable: false + isMapped: true + customer_full_name: + count: 0 + name: customer_full_name + type: string + esTypes: + - text + scripted: false + searchable: true + aggregatable: false + readFromDocValues: false + format: + id: string + shortDotsEnable: false + isMapped: true + customer_full_name.keyword: + count: 0 + name: customer_full_name.keyword + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + subType: + multi: + parent: customer_full_name + format: + id: string + shortDotsEnable: false + isMapped: true + customer_gender: + count: 0 + name: customer_gender + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + customer_id: + count: 0 + name: customer_id + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + customer_last_name: + count: 0 + name: customer_last_name + type: string + esTypes: + - text + scripted: false + searchable: true + aggregatable: false + readFromDocValues: false + format: + id: string + shortDotsEnable: false + isMapped: true + customer_last_name.keyword: + count: 0 + name: customer_last_name.keyword + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + subType: + multi: + parent: customer_last_name + format: + id: string + shortDotsEnable: false + isMapped: true + customer_phone: + count: 0 + name: customer_phone + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + day_of_week: + count: 0 + name: day_of_week + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + day_of_week_i: + count: 0 + name: day_of_week_i + type: number + esTypes: + - integer + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + shortDotsEnable: false + isMapped: true + email: + count: 0 + name: email + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + event.dataset: + count: 0 + name: event.dataset + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + geoip.city_name: + count: 0 + name: geoip.city_name + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + geoip.continent_name: + count: 0 + name: geoip.continent_name + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + geoip.country_iso_code: + count: 0 + name: geoip.country_iso_code + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + geoip.location: + count: 0 + name: geoip.location + type: geo_point + esTypes: + - geo_point + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: geo_point + params: + transform: wkt + shortDotsEnable: false + isMapped: true + geoip.region_name: + count: 0 + name: geoip.region_name + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + manufacturer: + count: 0 + name: manufacturer + type: string + esTypes: + - text + scripted: false + searchable: true + aggregatable: false + readFromDocValues: false + format: + id: string + shortDotsEnable: false + isMapped: true + manufacturer.keyword: + count: 0 + name: manufacturer.keyword + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + subType: + multi: + parent: manufacturer + format: + id: string + shortDotsEnable: false + isMapped: true + order_date: + count: 0 + name: order_date + type: date + esTypes: + - date + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: date + shortDotsEnable: false + isMapped: true + order_id: + count: 0 + name: order_id + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + products._id: + count: 0 + name: products._id + type: string + esTypes: + - text + scripted: false + searchable: true + aggregatable: false + readFromDocValues: false + format: + id: string + shortDotsEnable: false + isMapped: true + products._id.keyword: + count: 0 + name: products._id.keyword + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + subType: + multi: + parent: products._id + format: + id: string + shortDotsEnable: false + isMapped: true + products.base_price: + count: 0 + name: products.base_price + type: number + esTypes: + - half_float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + params: + pattern: $0,0.00 + shortDotsEnable: false + isMapped: true + products.base_unit_price: + count: 0 + name: products.base_unit_price + type: number + esTypes: + - half_float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + params: + pattern: $0,0.00 + shortDotsEnable: false + isMapped: true + products.category: + count: 0 + name: products.category + type: string + esTypes: + - text + scripted: false + searchable: true + aggregatable: false + readFromDocValues: false + format: + id: string + shortDotsEnable: false + isMapped: true + products.category.keyword: + count: 0 + name: products.category.keyword + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + subType: + multi: + parent: products.category + format: + id: string + shortDotsEnable: false + isMapped: true + products.created_on: + count: 0 + name: products.created_on + type: date + esTypes: + - date + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: date + shortDotsEnable: false + isMapped: true + products.discount_amount: + count: 0 + name: products.discount_amount + type: number + esTypes: + - half_float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + shortDotsEnable: false + isMapped: true + products.discount_percentage: + count: 0 + name: products.discount_percentage + type: number + esTypes: + - half_float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + shortDotsEnable: false + isMapped: true + products.manufacturer: + count: 1 + name: products.manufacturer + type: string + esTypes: + - text + scripted: false + searchable: true + aggregatable: false + readFromDocValues: false + format: + id: string + shortDotsEnable: false + isMapped: true + products.manufacturer.keyword: + count: 0 + name: products.manufacturer.keyword + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + subType: + multi: + parent: products.manufacturer + format: + id: string + shortDotsEnable: false + isMapped: true + products.min_price: + count: 0 + name: products.min_price + type: number + esTypes: + - half_float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + params: + pattern: $0,0.00 + shortDotsEnable: false + isMapped: true + products.price: + count: 1 + name: products.price + type: number + esTypes: + - half_float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + params: + pattern: $0,0.00 + shortDotsEnable: false + isMapped: true + products.product_id: + count: 0 + name: products.product_id + type: number + esTypes: + - long + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + shortDotsEnable: false + isMapped: true + products.product_name: + count: 1 + name: products.product_name + type: string + esTypes: + - text + scripted: false + searchable: true + aggregatable: false + readFromDocValues: false + format: + id: string + shortDotsEnable: false + isMapped: true + products.product_name.keyword: + count: 0 + name: products.product_name.keyword + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + subType: + multi: + parent: products.product_name + format: + id: string + shortDotsEnable: false + isMapped: true + products.quantity: + count: 0 + name: products.quantity + type: number + esTypes: + - integer + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + shortDotsEnable: false + isMapped: true + products.sku: + count: 0 + name: products.sku + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + products.tax_amount: + count: 0 + name: products.tax_amount + type: number + esTypes: + - half_float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + shortDotsEnable: false + isMapped: true + products.taxful_price: + count: 0 + name: products.taxful_price + type: number + esTypes: + - half_float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + params: + pattern: $0,0.00 + shortDotsEnable: false + isMapped: true + products.taxless_price: + count: 0 + name: products.taxless_price + type: number + esTypes: + - half_float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + params: + pattern: $0,0.00 + shortDotsEnable: false + isMapped: true + products.unit_discount_amount: + count: 0 + name: products.unit_discount_amount + type: number + esTypes: + - half_float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + shortDotsEnable: false + isMapped: true + sku: + count: 0 + name: sku + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + taxful_total_price: + count: 0 + name: taxful_total_price + type: number + esTypes: + - half_float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + params: + pattern: $0,0.[00] + shortDotsEnable: false + isMapped: true + taxless_total_price: + count: 0 + name: taxless_total_price + type: number + esTypes: + - half_float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + params: + pattern: $0,0.00 + shortDotsEnable: false + isMapped: true + total_quantity: + count: 1 + name: total_quantity + type: number + esTypes: + - integer + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + shortDotsEnable: false + isMapped: true + total_unique_products: + count: 0 + name: total_unique_products + type: number + esTypes: + - integer + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + shortDotsEnable: false + isMapped: true + type: + count: 0 + name: type + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + user: + count: 0 + name: user + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + typeMeta: {} + fieldFormats: + taxful_total_price: + id: number + params: + pattern: $0,0.[00] + products.price: + id: number + params: + pattern: $0,0.00 + taxless_total_price: + id: number + params: + pattern: $0,0.00 + products.taxless_price: + id: number + params: + pattern: $0,0.00 + products.taxful_price: + id: number + params: + pattern: $0,0.00 + products.min_price: + id: number + params: + pattern: $0,0.00 + products.base_unit_price: + id: number + params: + pattern: $0,0.00 + products.base_price: + id: number + params: + pattern: $0,0.00 + runtimeFieldMap: {} + fieldAttrs: + products.manufacturer: + count: 1 + products.price: + count: 1 + products.product_name: + count: 1 + total_quantity: + count: 1 + allowNoIndex: false + name: Kibana Sample Data eCommerce + namespaces: + - default + Data_views_update_data_view_request: + summary: Update some properties for a data view. + value: + data_view: + title: kibana_sample_data_ecommerce + timeFieldName: order_date + allowNoIndex: false + name: Kibana Sample Data eCommerce + refresh_fields: true + Data_views_get_default_data_view_response: + summary: The get default data view API returns the default data view identifier. + value: + data_view_id: ff959d40-b880-11e8-a6d9-e546fe2bba5f + Data_views_set_default_data_view_request: + summary: Set the default data view identifier. + value: + data_view_id: ff959d40-b880-11e8-a6d9-e546fe2bba5f + force: true + Data_views_update_field_metadata_request: + summary: Update multiple metadata fields. + value: + fields: + field1: + count: 123 + customLabel: Field 1 label + field2: + customLabel: Field 2 label + customDescription: Field 2 description + Data_views_create_runtime_field_request: + summary: Create a runtime field. + value: + name: runtimeFoo + runtimeField: + type: long + script: + source: emit(doc["foo"].value) + Data_views_get_runtime_field_response: + summary: >- + The get runtime field API returns a JSON object that contains + information about the runtime field (`hour_of_day`) and the data view + (`d3d7af60-4c81-11e8-b3d7-01146121b73d`). + value: + fields: + - count: 0 + name: hour_of_day + type: number + esTypes: + - long + scripted: false + searchable: true + aggregatable: true + readFromDocValues: false + shortDotsEnable: false + runtimeField: + type: long + script: + source: emit(doc['timestamp'].value.getHour()); + data_view: + id: d3d7af60-4c81-11e8-b3d7-01146121b73d + version: WzM2LDJd + title: kibana_sample_data_flights + timeFieldName: timestamp + sourceFilters: [] + fields: + hour_of_day: + count: 0 + name: hour_of_day + type: number + esTypes: + - long + scripted: false + searchable: true + aggregatable: true + readFromDocValues: false + format: + id: number + params: + pattern: '00' + shortDotsEnable: false + runtimeField: + type: long + script: + source: emit(doc['timestamp'].value.getHour()); + AvgTicketPrice: + count: 0 + name: AvgTicketPrice + type: number + esTypes: + - float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + params: + pattern: $0,0.[00] + shortDotsEnable: false + isMapped: true + Cancelled: + count: 0 + name: Cancelled + type: boolean + esTypes: + - boolean + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: boolean + shortDotsEnable: false + isMapped: true + Carrier: + count: 0 + name: Carrier + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + Dest: + count: 0 + name: Dest + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + DestAirportID: + count: 0 + name: DestAirportID + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + DestCityName: + count: 0 + name: DestCityName + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + DestCountry: + count: 0 + name: DestCountry + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + DestLocation: + count: 0 + name: DestLocation + type: geo_point + esTypes: + - geo_point + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: geo_point + params: + transform: wkt + shortDotsEnable: false + isMapped: true + DestRegion: + count: 0 + name: DestRegion + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + DestWeather: + count: 0 + name: DestWeather + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + DistanceKilometers: + count: 0 + name: DistanceKilometers + type: number + esTypes: + - float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + shortDotsEnable: false + isMapped: true + DistanceMiles: + count: 0 + name: DistanceMiles + type: number + esTypes: + - float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + shortDotsEnable: false + isMapped: true + FlightDelay: + count: 0 + name: FlightDelay + type: boolean + esTypes: + - boolean + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: boolean + shortDotsEnable: false + isMapped: true + FlightDelayMin: + count: 0 + name: FlightDelayMin + type: number + esTypes: + - integer + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + shortDotsEnable: false + isMapped: true + FlightDelayType: + count: 0 + name: FlightDelayType + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + FlightNum: + count: 0 + name: FlightNum + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + FlightTimeHour: + count: 0 + name: FlightTimeHour + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + FlightTimeMin: + count: 0 + name: FlightTimeMin + type: number + esTypes: + - float + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + shortDotsEnable: false + isMapped: true + Origin: + count: 0 + name: Origin + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + OriginAirportID: + count: 0 + name: OriginAirportID + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + OriginCityName: + count: 0 + name: OriginCityName + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + OriginCountry: + count: 0 + name: OriginCountry + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + OriginLocation: + count: 0 + name: OriginLocation + type: geo_point + esTypes: + - geo_point + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: geo_point + params: + transform: wkt + shortDotsEnable: false + isMapped: true + OriginRegion: + count: 0 + name: OriginRegion + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + OriginWeather: + count: 0 + name: OriginWeather + type: string + esTypes: + - keyword + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: string + shortDotsEnable: false + isMapped: true + _id: + count: 0 + name: _id + type: string + esTypes: + - _id + scripted: false + searchable: true + aggregatable: false + readFromDocValues: false + format: + id: string + shortDotsEnable: false + isMapped: true + _index: + count: 0 + name: _index + type: string + esTypes: + - _index + scripted: false + searchable: true + aggregatable: true + readFromDocValues: false + format: + id: string + shortDotsEnable: false + isMapped: true + _score: + count: 0 + name: _score + type: number + scripted: false + searchable: false + aggregatable: false + readFromDocValues: false + format: + id: number + shortDotsEnable: false + isMapped: true + _source: + count: 0 + name: _source + type: _source + esTypes: + - _source + scripted: false + searchable: false + aggregatable: false + readFromDocValues: false + format: + id: _source + shortDotsEnable: false + isMapped: true + dayOfWeek: + count: 0 + name: dayOfWeek + type: number + esTypes: + - integer + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: number + shortDotsEnable: false + isMapped: true + timestamp: + count: 0 + name: timestamp + type: date + esTypes: + - date + scripted: false + searchable: true + aggregatable: true + readFromDocValues: true + format: + id: date + shortDotsEnable: false + isMapped: true + fieldFormats: + hour_of_day: + id: number + params: + pattern: '00' + AvgTicketPrice: + id: number + params: + pattern: $0,0.[00] + runtimeFieldMap: + hour_of_day: + type: long + script: + source: emit(doc['timestamp'].value.getHour()); + fieldAttrs: {} + allowNoIndex: false + name: Kibana Sample Data Flights + Data_views_update_runtime_field_request: + summary: Update an existing runtime field on a data view. + value: + runtimeField: + script: + source: emit(doc["bar"].value) + Machine_learning_APIs_mlSyncExample: + summary: Two anomaly detection jobs required synchronization in this example. + value: + savedObjectsCreated: + anomaly-detector: + myjob1: + success: true + myjob2: + success: true + savedObjectsDeleted: {} + datafeedsAdded: {} + datafeedsRemoved: {} + Saved_objects_key_rotation_response: + summary: Encryption key rotation using default parameters. + value: + total: 1000 + successful: 300 + failed: 0 + Saved_objects_export_objects_request: + summary: Export a specific saved object. + value: + objects: + - type: map + id: de71f4f0-1902-11e9-919b-ffe5949a18d2 + includeReferencesDeep: false + excludeExportDetails: true + Saved_objects_export_objects_response: + summary: >- + The export objects API response contains a JSON record for each exported + object. + value: + attributes: + description: '' + layerListJSON: >- + [{"id":"0hmz5","alpha":1,"sourceDescriptor":{"type":"EMS_TMS","isAutoSelect":true,"lightModeDefault":"road_map_desaturated"},"visible":true,"style":{},"type":"EMS_VECTOR_TILE","minZoom":0,"maxZoom":24},{"id":"edh66","label":"Total + Requests by + Destination","minZoom":0,"maxZoom":24,"alpha":0.5,"sourceDescriptor":{"type":"EMS_FILE","id":"world_countries","tooltipProperties":["name","iso2"]},"visible":true,"style":{"type":"VECTOR","properties":{"fillColor":{"type":"DYNAMIC","options":{"field":{"name":"__kbnjoin__count__673ff994-fc75-4c67-909b-69fcb0e1060e","origin":"join"},"color":"Greys","fieldMetaOptions":{"isEnabled":false,"sigma":3}}},"lineColor":{"type":"STATIC","options":{"color":"#FFFFFF"}},"lineWidth":{"type":"STATIC","options":{"size":1}},"iconSize":{"type":"STATIC","options":{"size":10}},"symbolizeAs":{"options":{"value":"circle"}},"icon":{"type":"STATIC","options":{"value":"marker"}}}},"type":"GEOJSON_VECTOR","joins":[{"leftField":"iso2","right":{"type":"ES_TERM_SOURCE","id":"673ff994-fc75-4c67-909b-69fcb0e1060e","indexPatternTitle":"kibana_sample_data_logs","term":"geo.dest","indexPatternRefName":"layer_1_join_0_index_pattern","metrics":[{"type":"count","label":"web + logs + count"}],"applyGlobalQuery":true}}]},{"id":"gaxya","label":"Actual + Requests","minZoom":9,"maxZoom":24,"alpha":1,"sourceDescriptor":{"id":"b7486535-171b-4d3b-bb2e-33c1a0a2854c","type":"ES_SEARCH","geoField":"geo.coordinates","limit":2048,"filterByMapBounds":true,"tooltipProperties":["clientip","timestamp","host","request","response","machine.os","agent","bytes"],"indexPatternRefName":"layer_2_source_index_pattern","applyGlobalQuery":true,"scalingType":"LIMIT"},"visible":true,"style":{"type":"VECTOR","properties":{"fillColor":{"type":"STATIC","options":{"color":"#2200ff"}},"lineColor":{"type":"STATIC","options":{"color":"#FFFFFF"}},"lineWidth":{"type":"STATIC","options":{"size":2}},"iconSize":{"type":"DYNAMIC","options":{"field":{"name":"bytes","origin":"source"},"minSize":1,"maxSize":23,"fieldMetaOptions":{"isEnabled":false,"sigma":3}}},"symbolizeAs":{"options":{"value":"circle"}},"icon":{"type":"STATIC","options":{"value":"marker"}}}},"type":"GEOJSON_VECTOR"},{"id":"tfi3f","label":"Total + Requests and + Bytes","minZoom":0,"maxZoom":9,"alpha":1,"sourceDescriptor":{"type":"ES_GEO_GRID","resolution":"COARSE","id":"8aaa65b5-a4e9-448b-9560-c98cb1c5ac5b","geoField":"geo.coordinates","requestType":"point","metrics":[{"type":"count","label":"web + logs + count"},{"type":"sum","field":"bytes"}],"indexPatternRefName":"layer_3_source_index_pattern","applyGlobalQuery":true},"visible":true,"style":{"type":"VECTOR","properties":{"fillColor":{"type":"DYNAMIC","options":{"field":{"name":"doc_count","origin":"source"},"color":"Blues","fieldMetaOptions":{"isEnabled":false,"sigma":3}}},"lineColor":{"type":"STATIC","options":{"color":"#cccccc"}},"lineWidth":{"type":"STATIC","options":{"size":1}},"iconSize":{"type":"DYNAMIC","options":{"field":{"name":"sum_of_bytes","origin":"source"},"minSize":7,"maxSize":25,"fieldMetaOptions":{"isEnabled":false,"sigma":3}}},"labelText":{"type":"DYNAMIC","options":{"field":{"name":"doc_count","origin":"source"},"fieldMetaOptions":{"isEnabled":false,"sigma":3}}},"labelSize":{"type":"DYNAMIC","options":{"field":{"name":"doc_count","origin":"source"},"minSize":12,"maxSize":24,"fieldMetaOptions":{"isEnabled":false,"sigma":3}}},"symbolizeAs":{"options":{"value":"circle"}},"icon":{"type":"STATIC","options":{"value":"marker"}}}},"type":"GEOJSON_VECTOR"}] + mapStateJSON: >- + {"zoom":3.64,"center":{"lon":-88.92107,"lat":42.16337},"timeFilters":{"from":"now-7d","to":"now"},"refreshConfig":{"isPaused":true,"interval":0},"query":{"language":"kuery","query":""},"settings":{"autoFitToDataBounds":false}} + title: '[Logs] Total Requests and Bytes' + uiStateJSON: '{"isDarkMode":false}' + coreMigrationVersion: 8.8.0 + created_at: '2023-08-23T20:03:32.204Z' + id: de71f4f0-1902-11e9-919b-ffe5949a18d2 + managed: false + references: + - id: 90943e30-9a47-11e8-b64d-95841ca0b247 + name: layer_1_join_0_index_pattern + type: index-pattern + - id: 90943e30-9a47-11e8-b64d-95841ca0b247 + name: layer_2_source_index_pattern + type: index-pattern + - id: 90943e30-9a47-11e8-b64d-95841ca0b247 + name: layer_3_source_index_pattern + type: index-pattern + type: map + typeMigrationVersion: 8.4.0 + updated_at: '2023-08-23T20:03:32.204Z' + version: WzEzLDFd + Saved_objects_import_objects_request: + value: + file: file.ndjson + Saved_objects_import_objects_response: + summary: >- + The import objects API response indicates a successful import and the + objects are created. Since these objects are created as new copies, each + entry in the successResults array includes a destinationId attribute. + value: + successCount: 1 + success: true + successResults: + - type: index-pattern + id: 90943e30-9a47-11e8-b64d-95841ca0b247 + meta: + title: Kibana Sample Data Logs + icon: indexPatternApp + managed: false + destinationId: 82d2760c-468f-49cf-83aa-b9a35b6a8943 + Saved_objects_resolve_missing_reference_request: + value: + file: file.ndjson + retries: + - type: index-pattern + id: my-pattern + overwrite: true + - type: visualization + id: my-vis + overwrite: true + destinationId: another-vis + - type: canvas + id: my-canvas + overwrite: true + destinationId: yet-another-canvas + - type: dashboard + id: my-dashboard + Saved_objects_resolve_missing_reference_response: + summary: Resolve missing reference errors. + value: + success: true + successCount: 3 + successResults: + - id: my-vis + type: visualization + meta: + icon: visualizeApp + title: Look at my visualization + - id: my-search + type: search + meta: + icon: searchApp + title: Look at my search + - id: my-dashboard + type: dashboard + meta: + icon: dashboardApp + title: Look at my dashboard + responses: + Connectors_401: + description: Authorization information is missing or invalid. + content: + application/json: + schema: + type: object + title: Unauthorized response + properties: + error: + type: string + example: Unauthorized + enum: + - Unauthorized + message: + type: string + statusCode: + type: integer + example: 401 + enum: + - 401 + Connectors_404: + description: Object is not found. + content: + application/json: + schema: + type: object + title: Not found response + properties: + error: + type: string + example: Not Found + enum: + - Not Found + message: + type: string + example: >- + Saved object [action/baf33fc0-920c-11ed-b36a-874bd1548a00] not + found + statusCode: + type: integer + example: 404 + enum: + - 404 + Connectors_200_actions: + description: Indicates a successful call. + content: + application/json: + schema: + $ref: '#/components/schemas/Connectors_action_response_properties' +x-tagGroups: + - name: APM UI + tags: + - APM agent keys + - APM annotations + - name: Connectors + tags: + - connectors + - name: Data views + tags: + - data views + - name: Machine learning APIs + tags: + - ml + - name: Saved objects + tags: + - saved objects + - name: SLOs + tags: + - slo diff --git a/oas_docs/overlays/kibana.overlays.yaml b/oas_docs/overlays/kibana.overlays.yaml new file mode 100644 index 0000000000000..e33896791632b --- /dev/null +++ b/oas_docs/overlays/kibana.overlays.yaml @@ -0,0 +1,33 @@ +# overlays.yaml +overlay: 1.0.0 +info: + title: Overlays for the Kibana API document + version: 0.0.1 +actions: + - target: '$.servers.*' + description: Remove all servers so we can add our own. + remove: true + - target: '$.servers' + description: Add server into the now empty server array. + update: + - url: https://{kibana_url} + variables: + kibana_url: + default: localhost:5601 + # - target: '$.components.securitySchemes' + # description: Remove all security schemes so we can add our own. + # remove: true + # - target: '$.components' + # description: Add security schemes + # update: + # securitySchemes: + # basicAuth: + # type: http + # scheme: basic + # apiKeyAuth: + # type: apiKey + # in: header + # name: Authorization + # description: 'e.g. Authorization: ApiKey base64AccessApiKey' + # - target: '$.paths["/api/actions/connector"][*].security' + # remove: true diff --git a/package.json b/package.json index 899ec8c52d498..0b99d219a968e 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,7 @@ "@elastic/apm-rum": "^5.16.1", "@elastic/apm-rum-core": "^5.21.0", "@elastic/apm-rum-react": "^2.0.3", - "@elastic/charts": "66.0.5", + "@elastic/charts": "66.1.0", "@elastic/datemath": "5.0.3", "@elastic/ecs": "^8.11.1", "@elastic/elasticsearch": "^8.14.0", @@ -180,6 +180,7 @@ "@kbn/application-usage-test-plugin": "link:x-pack/test/usage_collection/plugins/application_usage_test", "@kbn/assets-data-access-plugin": "link:x-pack/plugins/observability_solution/assets_data_access", "@kbn/audit-log-plugin": "link:x-pack/test/security_api_integration/plugins/audit_log", + "@kbn/avc-banner": "link:packages/kbn-avc-banner", "@kbn/banners-plugin": "link:x-pack/plugins/banners", "@kbn/bfetch-error": "link:packages/kbn-bfetch-error", "@kbn/bfetch-explorer-plugin": "link:examples/bfetch_explorer", @@ -748,6 +749,7 @@ "@kbn/security-plugin-types-common": "link:x-pack/packages/security/plugin_types_common", "@kbn/security-plugin-types-public": "link:x-pack/packages/security/plugin_types_public", "@kbn/security-plugin-types-server": "link:x-pack/packages/security/plugin_types_server", + "@kbn/security-solution-distribution-bar": "link:x-pack/packages/security-solution/distribution_bar", "@kbn/security-solution-ess": "link:x-pack/plugins/security_solution_ess", "@kbn/security-solution-features": "link:x-pack/packages/security-solution/features", "@kbn/security-solution-fixtures-plugin": "link:x-pack/test/cases_api_integration/common/plugins/security_solution", @@ -1099,6 +1101,7 @@ "monaco-editor": "^0.44.0", "monaco-yaml": "^5.1.0", "mustache": "^2.3.2", + "node-diff3": "^3.1.2", "node-fetch": "^2.6.7", "node-forge": "^1.3.1", "nodemailer": "^6.9.14", @@ -1719,7 +1722,7 @@ "regenerate": "^1.4.0", "resolve": "^1.22.0", "rxjs-marbles": "^7.0.1", - "sass-embedded": "^1.77.5", + "sass-embedded": "^1.77.8", "sass-loader": "^10.5.1", "selenium-webdriver": "^4.22.0", "sharp": "0.32.6", diff --git a/packages/core/apps/core-apps-server-internal/src/core_app.ts b/packages/core/apps/core-apps-server-internal/src/core_app.ts index c29fb2d7cc096..e6b7349d2edff 100644 --- a/packages/core/apps/core-apps-server-internal/src/core_app.ts +++ b/packages/core/apps/core-apps-server-internal/src/core_app.ts @@ -113,7 +113,10 @@ export class CoreAppsService { { path: '/', validate: false, options: { access: 'public' } }, async (context, req, res) => { const { uiSettings } = await context.core; - const defaultRoute = await uiSettings.client.get('defaultRoute'); + let defaultRoute = await uiSettings.client.get('defaultRoute', { request: req }); + if (!defaultRoute) { + defaultRoute = '/app/home'; + } const basePath = httpSetup.basePath.get(req); const url = `${basePath}${defaultRoute}`; diff --git a/packages/core/chrome/core-chrome-browser/src/project_navigation.ts b/packages/core/chrome/core-chrome-browser/src/project_navigation.ts index 75f3b3be8edce..ca163bea2930f 100644 --- a/packages/core/chrome/core-chrome-browser/src/project_navigation.ts +++ b/packages/core/chrome/core-chrome-browser/src/project_navigation.ts @@ -431,7 +431,7 @@ export interface SolutionNavigationDefinition { // status is 'unknown' when auth is disabled. we just need to not be `unauthenticated` here. return authStatus !== 'unauthenticated'; }; + +/** + * Load async values from the definitions that have a `getValue()` function + * + * @param defaultSettings The default settings to add async values to + * @param request The current KibanaRequest + * @returns The default settings with values updated with async values + */ +const withAsyncDefaultValues = async ( + request: KibanaRequest, + defaultSettings: Readonly>> = {} +): Promise>>> => { + const updatedSettings = { ...defaultSettings }; + + await Promise.all( + Object.entries(defaultSettings) + .filter(([_, definition]) => typeof definition.getValue === 'function') + .map(([key, definition]) => { + return definition.getValue!({ request }).then((value) => { + updatedSettings[key] = { ...definition, value }; + }); + }) + ); + + return updatedSettings; +}; diff --git a/packages/core/ui-settings/core-ui-settings-common/index.ts b/packages/core/ui-settings/core-ui-settings-common/index.ts index e0dd04dec853a..461b167d7cb98 100644 --- a/packages/core/ui-settings/core-ui-settings-common/index.ts +++ b/packages/core/ui-settings/core-ui-settings-common/index.ts @@ -13,6 +13,7 @@ export type { UiSettingsParams, UserProvidedValues, UiSettingsScope, + GetUiSettingsContext, } from './src/ui_settings'; export { type DarkModeValue, parseDarkModeValue } from './src/dark_mode'; diff --git a/packages/core/ui-settings/core-ui-settings-common/src/ui_settings.ts b/packages/core/ui-settings/core-ui-settings-common/src/ui_settings.ts index 66ffcf2b7977d..c5acafabc7f94 100644 --- a/packages/core/ui-settings/core-ui-settings-common/src/ui_settings.ts +++ b/packages/core/ui-settings/core-ui-settings-common/src/ui_settings.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import type { KibanaRequest } from '@kbn/core-http-server'; import type { Type } from '@kbn/config-schema'; import type { UiCounterMetricType } from '@kbn/analytics'; @@ -44,6 +45,10 @@ export interface DeprecationSettings { docLinksKey: string; } +export interface GetUiSettingsContext { + request?: KibanaRequest; +} + /** * UiSettings parameters defined by the plugins. * @public @@ -53,6 +58,8 @@ export interface UiSettingsParams { name?: string; /** default value to fall back to if a user doesn't provide any */ value?: T; + /** handler to return the default value asynchronously. Supersedes the `value` prop */ + getValue?: (context?: GetUiSettingsContext) => Promise; /** description provided to a user in UI */ description?: string; /** used to group the configured setting in the UI */ diff --git a/packages/core/ui-settings/core-ui-settings-common/tsconfig.json b/packages/core/ui-settings/core-ui-settings-common/tsconfig.json index 3b43c09cbaa08..733581728ddb8 100644 --- a/packages/core/ui-settings/core-ui-settings-common/tsconfig.json +++ b/packages/core/ui-settings/core-ui-settings-common/tsconfig.json @@ -12,7 +12,8 @@ ], "kbn_references": [ "@kbn/config-schema", - "@kbn/analytics" + "@kbn/analytics", + "@kbn/core-http-server" ], "exclude": [ "target/**/*", diff --git a/packages/core/ui-settings/core-ui-settings-server-internal/src/clients/base_ui_settings_client.ts b/packages/core/ui-settings/core-ui-settings-server-internal/src/clients/base_ui_settings_client.ts index 3f65973c7ec2f..04da5a75788ec 100644 --- a/packages/core/ui-settings/core-ui-settings-server-internal/src/clients/base_ui_settings_client.ts +++ b/packages/core/ui-settings/core-ui-settings-server-internal/src/clients/base_ui_settings_client.ts @@ -8,7 +8,11 @@ import { omit } from 'lodash'; import type { Logger } from '@kbn/logging'; -import type { UiSettingsParams, UserProvidedValues } from '@kbn/core-ui-settings-common'; +import type { + GetUiSettingsContext, + UiSettingsParams, + UserProvidedValues, +} from '@kbn/core-ui-settings-common'; import type { IUiSettingsClient } from '@kbn/core-ui-settings-server'; import { ValidationBadValueError, ValidationSettingNotFoundError } from '../ui_settings_errors'; @@ -23,7 +27,6 @@ export interface BaseUiSettingsDefaultsClientOptions { */ export abstract class BaseUiSettingsClient implements IUiSettingsClient { private readonly defaults: Record; - private readonly defaultValues: Record; protected readonly overrides: Record; protected readonly log: Logger; @@ -33,9 +36,6 @@ export abstract class BaseUiSettingsClient implements IUiSettingsClient { this.overrides = overrides; this.defaults = defaults; - this.defaultValues = Object.fromEntries( - Object.entries(this.defaults).map(([key, { value }]) => [key, value]) - ); } getRegistered() { @@ -46,13 +46,14 @@ export abstract class BaseUiSettingsClient implements IUiSettingsClient { return copiedDefaults; } - async get(key: string): Promise { - const all = await this.getAll(); + async get(key: string, context?: GetUiSettingsContext): Promise { + const all = await this.getAll(context); return all[key] as T; } - async getAll() { - const result = { ...this.defaultValues }; + async getAll(context?: GetUiSettingsContext) { + const defaultValues = await this.getDefaultValues(context); + const result = { ...defaultValues }; const userProvided = await this.getUserProvided(); Object.keys(userProvided).forEach((key) => { @@ -99,6 +100,35 @@ export abstract class BaseUiSettingsClient implements IUiSettingsClient { } } + private async getDefaultValues(context?: GetUiSettingsContext) { + const values: { [key: string]: unknown } = {}; + const promises: Array<[string, Promise]> = []; + + for (const [key, definition] of Object.entries(this.defaults)) { + if (definition.getValue) { + promises.push([key, definition.getValue(context)]); + } else { + values[key] = definition.value; + } + } + + await Promise.all( + promises.map(([key, promise]) => + promise + .then((value) => { + values[key] = value; + }) + .catch((error) => { + this.log.error(`[UiSettingsClient] Failed to get value for key "${key}": ${error}`); + // Fallback to `value` prop if `getValue()` fails + values[key] = this.defaults[key].value; + }) + ) + ); + + return values; + } + abstract getUserProvided(): Promise>>; abstract setMany(changes: Record): Promise; diff --git a/packages/core/ui-settings/core-ui-settings-server-internal/src/clients/ui_settings_defaults_client.test.ts b/packages/core/ui-settings/core-ui-settings-server-internal/src/clients/ui_settings_defaults_client.test.ts index f16ffed8b506b..6596d7ee2aa19 100644 --- a/packages/core/ui-settings/core-ui-settings-server-internal/src/clients/ui_settings_defaults_client.test.ts +++ b/packages/core/ui-settings/core-ui-settings-server-internal/src/clients/ui_settings_defaults_client.test.ts @@ -62,6 +62,43 @@ describe('ui settings defaults', () => { result.foo = 'bar'; }).toThrow(); }); + + it('returns default values from async getValue() handler', async () => { + const defaults = { + foo: { + schema: schema.string(), + getValue: async () => { + // simulate async operation + await new Promise((resolve) => setTimeout(resolve, 200)); + return 'default foo'; + }, + }, + baz: { schema: schema.string(), value: 'default baz' }, + }; + + const uiSettings = new UiSettingsDefaultsClient({ defaults, log: logger }); + + await expect(uiSettings.getAll()).resolves.toStrictEqual({ + foo: 'default foo', + baz: 'default baz', + }); + }); + + it('pass down the context object to the getValue() handler', async () => { + const getValue = jest.fn().mockResolvedValue('default foo'); + const defaults = { + foo: { + schema: schema.string(), + getValue, + }, + }; + + const uiSettings = new UiSettingsDefaultsClient({ defaults, log: logger }); + + const context = { foo: 'bar' }; + await uiSettings.getAll(context as any); + expect(getValue).toHaveBeenCalledWith(context); + }); }); describe('#get()', () => { @@ -94,6 +131,38 @@ describe('ui settings defaults', () => { await expect(uiSettings.get('foo')).resolves.toBe('default foo'); }); + + it('returns default values from async getValue() handler', async () => { + const defaults = { + foo: { + schema: schema.string(), + getValue: async () => { + // simulate async operation + await new Promise((resolve) => setTimeout(resolve, 200)); + return 'default foo'; + }, + }, + }; + + const uiSettings = new UiSettingsDefaultsClient({ defaults, log: logger }); + await expect(uiSettings.get('foo')).resolves.toBe('default foo'); + }); + + it('pass down the context object to the getValue() handler', async () => { + const getValue = jest.fn().mockResolvedValue('default foo'); + const defaults = { + foo: { + schema: schema.string(), + getValue, + }, + }; + + const uiSettings = new UiSettingsDefaultsClient({ defaults, log: logger }); + + const context = { foo: 'bar' }; + await uiSettings.get('foo', context as any); + expect(getValue).toHaveBeenCalledWith(context); + }); }); describe('#setMany()', () => { diff --git a/packages/core/ui-settings/core-ui-settings-server-internal/src/settings/index.test.ts b/packages/core/ui-settings/core-ui-settings-server-internal/src/settings/index.test.ts index 5b4323f8663c5..aa348e90f2c41 100644 --- a/packages/core/ui-settings/core-ui-settings-server-internal/src/settings/index.test.ts +++ b/packages/core/ui-settings/core-ui-settings-server-internal/src/settings/index.test.ts @@ -9,7 +9,6 @@ import { getAccessibilitySettings } from './accessibility'; import { getDateFormatSettings } from './date_formats'; import { getMiscUiSettings } from './misc'; -import { getNavigationSettings } from './navigation'; import { getNotificationsSettings } from './notifications'; import { getThemeSettings } from './theme'; import { getCoreSettings } from '.'; @@ -24,7 +23,6 @@ describe('getCoreSettings', () => { getAnnouncementsSettings(), getDateFormatSettings(), getMiscUiSettings(), - getNavigationSettings(), getNotificationsSettings(), getThemeSettings(), getStateSettings(), diff --git a/packages/core/ui-settings/core-ui-settings-server-internal/src/settings/index.ts b/packages/core/ui-settings/core-ui-settings-server-internal/src/settings/index.ts index baf10af09acb6..9d7fc6686e26f 100644 --- a/packages/core/ui-settings/core-ui-settings-server-internal/src/settings/index.ts +++ b/packages/core/ui-settings/core-ui-settings-server-internal/src/settings/index.ts @@ -10,7 +10,6 @@ import type { UiSettingsParams } from '@kbn/core-ui-settings-common'; import { getAccessibilitySettings } from './accessibility'; import { getDateFormatSettings } from './date_formats'; import { getMiscUiSettings } from './misc'; -import { getNavigationSettings } from './navigation'; import { getNotificationsSettings } from './notifications'; import { getThemeSettings } from './theme'; import { getStateSettings } from './state'; @@ -28,7 +27,6 @@ export const getCoreSettings = ( ...getAnnouncementsSettings(), ...getDateFormatSettings(), ...getMiscUiSettings(), - ...getNavigationSettings(), ...getNotificationsSettings(), ...getThemeSettings(options), ...getStateSettings(), diff --git a/packages/core/ui-settings/core-ui-settings-server-internal/src/settings/navigation.test.ts b/packages/core/ui-settings/core-ui-settings-server-internal/src/settings/navigation.test.ts deleted file mode 100644 index 11c89c7662122..0000000000000 --- a/packages/core/ui-settings/core-ui-settings-server-internal/src/settings/navigation.test.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import type { UiSettingsParams } from '@kbn/core-ui-settings-common'; -import { getNavigationSettings } from './navigation'; - -describe('navigation settings', () => { - const navigationSettings = getNavigationSettings(); - - const getValidationFn = (setting: UiSettingsParams) => (value: any) => - setting.schema.validate(value); - - describe('defaultRoute', () => { - const validate = getValidationFn(navigationSettings.defaultRoute); - - it('should only accept relative urls', () => { - expect(() => validate('/some-url')).not.toThrow(); - expect(() => validate('http://some-url')).toThrowErrorMatchingInlineSnapshot( - `"Must be a relative URL."` - ); - expect(() => validate(125)).toThrowErrorMatchingInlineSnapshot( - `"expected value of type [string] but got [number]"` - ); - }); - }); -}); diff --git a/packages/core/ui-settings/core-ui-settings-server-internal/src/settings/navigation.ts b/packages/core/ui-settings/core-ui-settings-server-internal/src/settings/navigation.ts deleted file mode 100644 index c69889b84fc36..0000000000000 --- a/packages/core/ui-settings/core-ui-settings-server-internal/src/settings/navigation.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { schema } from '@kbn/config-schema'; -import { i18n } from '@kbn/i18n'; -import { isRelativeUrl } from '@kbn/std'; -import type { UiSettingsParams } from '@kbn/core-ui-settings-common'; - -export const getNavigationSettings = (): Record => { - return { - defaultRoute: { - name: i18n.translate('core.ui_settings.params.defaultRoute.defaultRouteTitle', { - defaultMessage: 'Default route', - }), - value: '/app/home', - schema: schema.string({ - validate(value) { - if (!value.startsWith('/') || !isRelativeUrl(value)) { - return i18n.translate( - 'core.ui_settings.params.defaultRoute.defaultRouteIsRelativeValidationMessage', - { - defaultMessage: 'Must be a relative URL.', - } - ); - } - }, - }), - description: i18n.translate('core.ui_settings.params.defaultRoute.defaultRouteText', { - defaultMessage: - 'This setting specifies the default route when opening Kibana. ' + - 'You can use this setting to modify the landing page when opening Kibana. ' + - 'The route must be a relative URL.', - }), - }, - }; -}; diff --git a/packages/core/ui-settings/core-ui-settings-server-internal/src/ui_settings_service.ts b/packages/core/ui-settings/core-ui-settings-server-internal/src/ui_settings_service.ts index 63b3ef7f66262..02dfd1562c3b3 100644 --- a/packages/core/ui-settings/core-ui-settings-server-internal/src/ui_settings_service.ts +++ b/packages/core/ui-settings/core-ui-settings-server-internal/src/ui_settings_service.ts @@ -218,13 +218,17 @@ export class UiSettingsService if (!definition.schema) { throw new Error(`Validation schema is not provided for [${key}] UI Setting`); } - definition.schema.validate(definition.value, {}, `ui settings defaults [${key}]`); + if (definition.value) { + definition.schema.validate(definition.value, {}, `ui settings defaults [${key}]`); + } } for (const [key, definition] of this.uiSettingsGlobalDefaults) { if (!definition.schema) { throw new Error(`Validation schema is not provided for [${key}] Global UI Setting`); } - definition.schema.validate(definition.value, {}); + if (definition.value) { + definition.schema.validate(definition.value, {}); + } } } diff --git a/packages/core/ui-settings/core-ui-settings-server/src/ui_settings_client.ts b/packages/core/ui-settings/core-ui-settings-server/src/ui_settings_client.ts index daf6bf43271b6..2f3d967cce15a 100644 --- a/packages/core/ui-settings/core-ui-settings-server/src/ui_settings_client.ts +++ b/packages/core/ui-settings/core-ui-settings-server/src/ui_settings_client.ts @@ -6,7 +6,11 @@ * Side Public License, v 1. */ -import type { UserProvidedValues, UiSettingsParams } from '@kbn/core-ui-settings-common'; +import type { + UserProvidedValues, + UiSettingsParams, + GetUiSettingsContext, +} from '@kbn/core-ui-settings-common'; interface ValueValidation { valid: boolean; @@ -29,11 +33,11 @@ export interface IUiSettingsClient { /** * Retrieves uiSettings values set by the user with fallbacks to default values if not specified. */ - get: (key: string) => Promise; + get: (key: string, context?: GetUiSettingsContext) => Promise; /** * Retrieves a set of all uiSettings values set by the user with fallbacks to default values if not specified. */ - getAll: () => Promise>; + getAll: (context?: GetUiSettingsContext) => Promise>; /** * Retrieves a set of all uiSettings values set by the user. */ diff --git a/packages/kbn-actions-types/action_types.ts b/packages/kbn-actions-types/action_types.ts new file mode 100644 index 0000000000000..7b76a82e29891 --- /dev/null +++ b/packages/kbn-actions-types/action_types.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { LicenseType } from '@kbn/licensing-plugin/common/types'; + +export interface ActionType { + id: string; + name: string; + enabled: boolean; + enabledInConfig: boolean; + enabledInLicense: boolean; + minimumLicenseRequired: LicenseType; + supportedFeatureIds: string[]; + isSystemActionType: boolean; +} diff --git a/packages/kbn-actions-types/index.ts b/packages/kbn-actions-types/index.ts index 12ae3bab43ddd..92ac3f5b87699 100644 --- a/packages/kbn-actions-types/index.ts +++ b/packages/kbn-actions-types/index.ts @@ -7,3 +7,4 @@ */ export * from './rewrite_request_case_types'; +export * from './action_types'; diff --git a/packages/kbn-actions-types/tsconfig.json b/packages/kbn-actions-types/tsconfig.json index 87f865132f4b4..f581a6d61b88f 100644 --- a/packages/kbn-actions-types/tsconfig.json +++ b/packages/kbn-actions-types/tsconfig.json @@ -15,5 +15,7 @@ "exclude": [ "target/**/*" ], - "kbn_references": [] + "kbn_references": [ + "@kbn/licensing-plugin", + ] } diff --git a/packages/kbn-alerts-ui-shared/src/action_variables/action_variables.ts b/packages/kbn-alerts-ui-shared/src/action_variables/action_variables.ts new file mode 100644 index 0000000000000..0ef0aad8509ee --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/action_variables/action_variables.ts @@ -0,0 +1,263 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { + ActionContextVariablesFlatten, + ActionVariable, + SummaryActionContextVariablesFlatten, +} from '@kbn/alerting-types'; +import { i18n } from '@kbn/i18n'; + +export enum AlertProvidedActionVariables { + ruleId = 'rule.id', + ruleName = 'rule.name', + ruleSpaceId = 'rule.spaceId', + ruleTags = 'rule.tags', + ruleType = 'rule.type', + ruleUrl = 'rule.url', + ruleParams = 'rule.params', + date = 'date', + alertId = 'alert.id', + alertUuid = 'alert.uuid', + alertActionGroup = 'alert.actionGroup', + alertActionGroupName = 'alert.actionGroupName', + alertActionSubgroup = 'alert.actionSubgroup', + alertFlapping = 'alert.flapping', + kibanaBaseUrl = 'kibanaBaseUrl', + alertConsecutiveMatches = 'alert.consecutiveMatches', +} + +export enum LegacyAlertProvidedActionVariables { + alertId = 'alertId', + alertName = 'alertName', + alertInstanceId = 'alertInstanceId', + alertActionGroup = 'alertActionGroup', + alertActionGroupName = 'alertActionGroupName', + alertActionSubgroup = 'alertActionSubgroup', + tags = 'tags', + spaceId = 'spaceId', + params = 'params', +} + +export enum SummaryAlertProvidedActionVariables { + newAlertsCount = 'alerts.new.count', + newAlertsData = 'alerts.new.data', + ongoingAlertsCount = 'alerts.ongoing.count', + ongoingAlertsData = 'alerts.ongoing.data', + recoveredAlertsCount = 'alerts.recovered.count', + recoveredAlertsData = 'alerts.recovered.data', + allAlertsCount = 'alerts.all.count', + allAlertsData = 'alerts.all.data', +} + +type ActionVariablesWithoutName = Omit; + +export const AlertProvidedActionVariableDescriptions: Record< + ActionContextVariablesFlatten, + ActionVariablesWithoutName +> = Object.freeze({ + [LegacyAlertProvidedActionVariables.alertId]: { + description: i18n.translate('alertsUIShared.actionVariables.legacyAlertIdLabel', { + defaultMessage: 'This has been deprecated in favor of {variable}.', + values: { + variable: AlertProvidedActionVariables.ruleId, + }, + }), + deprecated: true, + }, + [LegacyAlertProvidedActionVariables.alertName]: { + deprecated: true, + description: i18n.translate('alertsUIShared.actionVariables.legacyAlertNameLabel', { + defaultMessage: 'This has been deprecated in favor of {variable}.', + values: { + variable: AlertProvidedActionVariables.ruleName, + }, + }), + }, + [LegacyAlertProvidedActionVariables.alertInstanceId]: { + deprecated: true, + description: i18n.translate('alertsUIShared.actionVariables.legacyAlertInstanceIdLabel', { + defaultMessage: 'This has been deprecated in favor of {variable}.', + values: { + variable: AlertProvidedActionVariables.alertId, + }, + }), + }, + [LegacyAlertProvidedActionVariables.alertActionGroup]: { + deprecated: true, + description: i18n.translate('alertsUIShared.actionVariables.legacyAlertActionGroupLabel', { + defaultMessage: 'This has been deprecated in favor of {variable}.', + values: { + variable: AlertProvidedActionVariables.alertActionGroup, + }, + }), + }, + [LegacyAlertProvidedActionVariables.alertActionGroupName]: { + deprecated: true, + description: i18n.translate('alertsUIShared.actionVariables.legacyAlertActionGroupNameLabel', { + defaultMessage: 'This has been deprecated in favor of {variable}.', + values: { + variable: AlertProvidedActionVariables.alertActionGroupName, + }, + }), + }, + [LegacyAlertProvidedActionVariables.tags]: { + deprecated: true, + description: i18n.translate('alertsUIShared.actionVariables.legacyTagsLabel', { + defaultMessage: 'This has been deprecated in favor of {variable}.', + values: { + variable: AlertProvidedActionVariables.ruleTags, + }, + }), + }, + [LegacyAlertProvidedActionVariables.spaceId]: { + deprecated: true, + description: i18n.translate('alertsUIShared.actionVariables.legacySpaceIdLabel', { + defaultMessage: 'This has been deprecated in favor of {variable}.', + values: { + variable: AlertProvidedActionVariables.ruleSpaceId, + }, + }), + }, + [LegacyAlertProvidedActionVariables.params]: { + deprecated: true, + description: i18n.translate('alertsUIShared.actionVariables.legacyParamsLabel', { + defaultMessage: 'This has been deprecated in favor of {variable}.', + values: { + variable: AlertProvidedActionVariables.ruleParams, + }, + }), + }, + [AlertProvidedActionVariables.date]: { + description: i18n.translate('alertsUIShared.actionVariables.dateLabel', { + defaultMessage: 'The date the rule scheduled the action.', + }), + }, + [AlertProvidedActionVariables.kibanaBaseUrl]: { + description: i18n.translate('alertsUIShared.actionVariables.kibanaBaseUrlLabel', { + defaultMessage: + 'The configured server.publicBaseUrl value or empty string if not configured.', + }), + }, + [AlertProvidedActionVariables.ruleId]: { + description: i18n.translate('alertsUIShared.actionVariables.ruleIdLabel', { + defaultMessage: 'The ID of the rule.', + }), + }, + [AlertProvidedActionVariables.ruleName]: { + description: i18n.translate('alertsUIShared.actionVariables.ruleNameLabel', { + defaultMessage: 'The name of the rule.', + }), + }, + [AlertProvidedActionVariables.ruleSpaceId]: { + description: i18n.translate('alertsUIShared.actionVariables.ruleSpaceIdLabel', { + defaultMessage: 'The space ID of the rule.', + }), + }, + [AlertProvidedActionVariables.ruleType]: { + description: i18n.translate('alertsUIShared.actionVariables.ruleTypeLabel', { + defaultMessage: 'The type of rule.', + }), + }, + [AlertProvidedActionVariables.ruleTags]: { + description: i18n.translate('alertsUIShared.actionVariables.ruleTagsLabel', { + defaultMessage: 'The tags of the rule.', + }), + }, + [AlertProvidedActionVariables.ruleParams]: { + description: i18n.translate('alertsUIShared.actionVariables.ruleParamsLabel', { + defaultMessage: 'The parameters of the rule.', + }), + }, + [AlertProvidedActionVariables.ruleUrl]: { + description: i18n.translate('alertsUIShared.actionVariables.ruleUrlLabel', { + defaultMessage: + 'The URL to the rule that generated the alert. This will be an empty string if the server.publicBaseUrl is not configured.', + }), + usesPublicBaseUrl: true, + }, + [AlertProvidedActionVariables.alertId]: { + description: i18n.translate('alertsUIShared.actionVariables.alertIdLabel', { + defaultMessage: 'The ID of the alert that scheduled actions for the rule.', + }), + }, + [AlertProvidedActionVariables.alertUuid]: { + description: i18n.translate('alertsUIShared.actionVariables.alertUuidLabel', { + defaultMessage: 'The UUID of the alert that scheduled actions for the rule.', + }), + }, + [AlertProvidedActionVariables.alertActionGroup]: { + description: i18n.translate('alertsUIShared.actionVariables.alertActionGroupLabel', { + defaultMessage: 'The action group of the alert that scheduled actions for the rule.', + }), + }, + [AlertProvidedActionVariables.alertActionGroupName]: { + description: i18n.translate('alertsUIShared.actionVariables.alertActionGroupNameLabel', { + defaultMessage: + 'The human readable name of the action group of the alert that scheduled actions for the rule.', + }), + }, + [AlertProvidedActionVariables.alertFlapping]: { + description: i18n.translate('alertsUIShared.actionVariables.alertFlappingLabel', { + defaultMessage: + 'A flag on the alert that indicates whether the alert status is changing repeatedly.', + }), + }, + [AlertProvidedActionVariables.alertConsecutiveMatches]: { + description: i18n.translate('alertsUIShared.actionVariables.alertConsecutiveMatchesLabel', { + defaultMessage: 'The number of consecutive runs that meet the rule conditions.', + }), + }, +}); + +export const SummarizedAlertProvidedActionVariableDescriptions: Record< + SummaryActionContextVariablesFlatten, + Omit +> = Object.freeze({ + ...AlertProvidedActionVariableDescriptions, + [SummaryAlertProvidedActionVariables.allAlertsCount]: { + description: i18n.translate('alertsUIShared.actionVariables.allAlertsCountLabel', { + defaultMessage: 'The count of all alerts.', + }), + }, + [SummaryAlertProvidedActionVariables.allAlertsData]: { + description: i18n.translate('alertsUIShared.actionVariables.allAlertsDataLabel', { + defaultMessage: 'An array of objects for all alerts.', + }), + }, + [SummaryAlertProvidedActionVariables.newAlertsCount]: { + description: i18n.translate('alertsUIShared.actionVariables.newAlertsCountLabel', { + defaultMessage: 'The count of new alerts.', + }), + }, + [SummaryAlertProvidedActionVariables.newAlertsData]: { + description: i18n.translate('alertsUIShared.actionVariables.newAlertsDataLabel', { + defaultMessage: 'An array of objects for new alerts.', + }), + }, + [SummaryAlertProvidedActionVariables.ongoingAlertsCount]: { + description: i18n.translate('alertsUIShared.actionVariables.ongoingAlertsCountLabel', { + defaultMessage: 'The count of ongoing alerts.', + }), + }, + [SummaryAlertProvidedActionVariables.ongoingAlertsData]: { + description: i18n.translate('alertsUIShared.actionVariables.ongoingAlertsDataLabel', { + defaultMessage: 'An array of objects for ongoing alerts.', + }), + }, + [SummaryAlertProvidedActionVariables.recoveredAlertsCount]: { + description: i18n.translate('alertsUIShared.actionVariables.recoveredAlertsCountLabel', { + defaultMessage: 'The count of recovered alerts.', + }), + }, + [SummaryAlertProvidedActionVariables.recoveredAlertsData]: { + description: i18n.translate('alertsUIShared.actionVariables.recoveredAlertsDataLabel', { + defaultMessage: 'An array of objects for recovered alerts.', + }), + }, +}); diff --git a/packages/kbn-alerts-ui-shared/src/action_variables/get_available_action_variables.ts b/packages/kbn-alerts-ui-shared/src/action_variables/get_available_action_variables.ts new file mode 100644 index 0000000000000..7500af0051238 --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/action_variables/get_available_action_variables.ts @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { partition } from 'lodash'; +import { ActionVariable } from '@kbn/alerting-types'; +import { ActionGroupWithMessageVariables, ActionVariables } from '@kbn/triggers-actions-ui-types'; +import { transformActionVariables } from './transforms'; + +export const getAvailableActionVariables = ( + actionVariables: ActionVariables, + summaryActionVariables?: ActionVariables, + actionGroup?: ActionGroupWithMessageVariables, + isSummaryAction?: boolean +) => { + const transformedActionVariables: ActionVariable[] = transformActionVariables( + actionVariables, + summaryActionVariables, + actionGroup?.omitMessageVariables, + isSummaryAction + ); + + // partition deprecated items so they show up last + const partitionedActionVariables = partition( + transformedActionVariables, + (v) => v.deprecated !== true + ); + return partitionedActionVariables.reduce((acc, curr) => { + return [ + ...acc, + ...curr.sort((a, b) => a.name.toUpperCase().localeCompare(b.name.toUpperCase())), + ]; + }, []); +}; diff --git a/packages/kbn-alerts-ui-shared/src/action_variables/index.ts b/packages/kbn-alerts-ui-shared/src/action_variables/index.ts new file mode 100644 index 0000000000000..c6bf945bc81be --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/action_variables/index.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * from './action_variables'; +export * from './get_available_action_variables'; +export * from './transforms'; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/action_variables.test.ts b/packages/kbn-alerts-ui-shared/src/action_variables/transforms.test.ts similarity index 95% rename from x-pack/plugins/triggers_actions_ui/public/application/lib/action_variables.test.ts rename to packages/kbn-alerts-ui-shared/src/action_variables/transforms.test.ts index ef1c6f531848a..6bea78eb0b490 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/action_variables.test.ts +++ b/packages/kbn-alerts-ui-shared/src/action_variables/transforms.test.ts @@ -1,13 +1,14 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. */ -import { RuleType, ActionVariables } from '../../types'; -import { transformActionVariables } from './action_variables'; -import { ALERTING_FEATURE_ID } from '@kbn/alerting-plugin/common'; +import { ActionVariables, RuleType } from '@kbn/triggers-actions-ui-types'; +import { transformActionVariables } from './transforms'; +import { ALERTING_FEATURE_ID } from '../rule_form'; beforeEach(() => jest.resetAllMocks()); diff --git a/packages/kbn-alerts-ui-shared/src/action_variables/transforms.ts b/packages/kbn-alerts-ui-shared/src/action_variables/transforms.ts new file mode 100644 index 0000000000000..cf59bc3bdfe93 --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/action_variables/transforms.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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ActionVariable } from '@kbn/alerting-types'; +import { + ActionVariables, + OmitMessageVariablesType, + REQUIRED_ACTION_VARIABLES, + CONTEXT_ACTION_VARIABLES, +} from '@kbn/triggers-actions-ui-types'; +import { pick } from 'lodash'; +import { + AlertProvidedActionVariableDescriptions, + SummarizedAlertProvidedActionVariableDescriptions, +} from './action_variables'; + +type ActionVariablesWithoutName = Omit; + +const prefixKeys = (actionVariables: ActionVariable[], prefix: string): ActionVariable[] => { + return actionVariables.map((actionVariable) => { + return { ...actionVariable, name: `${prefix}${actionVariable.name}` }; + }); +}; + +export const getSummaryAlertActionVariables = (): ActionVariable[] => { + return transformContextVariables(SummarizedAlertProvidedActionVariableDescriptions); +}; + +export const getAlwaysProvidedActionVariables = (): ActionVariable[] => { + return transformContextVariables(AlertProvidedActionVariableDescriptions); +}; + +const transformProvidedActionVariables = ( + actionVariables?: ActionVariables, + omitMessageVariables?: OmitMessageVariablesType +): ActionVariable[] => { + if (!actionVariables) { + return []; + } + + const filteredActionVariables: ActionVariables = omitMessageVariables + ? omitMessageVariables === 'all' + ? pick(actionVariables, REQUIRED_ACTION_VARIABLES) + : pick(actionVariables, [...REQUIRED_ACTION_VARIABLES, ...CONTEXT_ACTION_VARIABLES]) + : actionVariables; + + const paramsVars = prefixKeys(filteredActionVariables.params, 'rule.params.'); + const contextVars = filteredActionVariables.context + ? prefixKeys(filteredActionVariables.context, 'context.') + : []; + const stateVars = filteredActionVariables.state + ? prefixKeys(filteredActionVariables.state, 'state.') + : []; + + return contextVars.concat(paramsVars, stateVars); +}; + +// return a "flattened" list of action variables for an alertType +export const transformActionVariables = ( + actionVariables: ActionVariables, + summaryActionVariables?: ActionVariables, + omitMessageVariables?: OmitMessageVariablesType, + isSummaryAction?: boolean +): ActionVariable[] => { + if (isSummaryAction) { + const alwaysProvidedVars = getSummaryAlertActionVariables(); + const transformedActionVars = transformProvidedActionVariables( + summaryActionVariables, + omitMessageVariables + ); + return alwaysProvidedVars.concat(transformedActionVars); + } + + const alwaysProvidedVars = getAlwaysProvidedActionVariables(); + const transformedActionVars = transformProvidedActionVariables( + actionVariables, + omitMessageVariables + ); + return alwaysProvidedVars.concat(transformedActionVars); +}; + +const transformContextVariables = ( + variables: Record +): ActionVariable[] => + Object.entries(variables).map(([key, variable]) => ({ ...variable, name: key })); diff --git a/packages/kbn-alerts-ui-shared/src/common/apis/fetch_aad_fields.ts b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_aad_fields.ts deleted file mode 100644 index 2bbfb698fb79d..0000000000000 --- a/packages/kbn-alerts-ui-shared/src/common/apis/fetch_aad_fields.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import type { HttpStart } from '@kbn/core/public'; -import type { DataViewField } from '@kbn/data-views-plugin/common'; -import { BASE_RAC_ALERTS_API_PATH, EMPTY_AAD_FIELDS } from '../constants'; - -export async function fetchAadFields({ - http, - ruleTypeId, -}: { - http: HttpStart; - ruleTypeId?: string; -}): Promise { - if (!ruleTypeId) return EMPTY_AAD_FIELDS; - const fields = await http.get(`${BASE_RAC_ALERTS_API_PATH}/aad_fields`, { - query: { ruleTypeId }, - }); - - return fields; -} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/action_connector_api/connector_types.test.ts b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_connector_types/fetch_connector_types.test.ts similarity index 90% rename from x-pack/plugins/triggers_actions_ui/public/application/lib/action_connector_api/connector_types.test.ts rename to packages/kbn-alerts-ui-shared/src/common/apis/fetch_connector_types/fetch_connector_types.test.ts index e5575ba28fad5..df1a393850ad4 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/action_connector_api/connector_types.test.ts +++ b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_connector_types/fetch_connector_types.test.ts @@ -1,13 +1,14 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. */ -import { ActionType } from '../../../types'; import { httpServiceMock } from '@kbn/core/public/mocks'; -import { loadActionTypes } from '.'; +import { fetchConnectorTypes } from './fetch_connector_types'; +import { ActionType } from '@kbn/actions-types'; const http = httpServiceMock.createStartContract(); @@ -42,7 +43,7 @@ describe('loadActionTypes', () => { }, ]; - const result = await loadActionTypes({ http }); + const result = await fetchConnectorTypes({ http }); expect(result).toEqual(resolvedValue); expect(http.get.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -80,7 +81,7 @@ describe('loadActionTypes', () => { }, ]; - const result = await loadActionTypes({ http, featureId: 'alerting' }); + const result = await fetchConnectorTypes({ http, featureId: 'alerting' }); expect(result).toEqual(resolvedValue); expect(http.get.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -143,7 +144,7 @@ describe('loadActionTypes', () => { }, ]; - const result = await loadActionTypes({ http, includeSystemActions: true }); + const result = await fetchConnectorTypes({ http, includeSystemActions: true }); expect(result).toEqual(resolvedValue); expect(http.get.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -202,7 +203,7 @@ describe('loadActionTypes', () => { }, ]; - const result = await loadActionTypes({ + const result = await fetchConnectorTypes({ http, featureId: 'alerting', includeSystemActions: true, diff --git a/packages/kbn-alerts-ui-shared/src/common/apis/fetch_connector_types/fetch_connector_types.ts b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_connector_types/fetch_connector_types.ts new file mode 100644 index 0000000000000..046460da3382e --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_connector_types/fetch_connector_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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { HttpSetup } from '@kbn/core/public'; +import { ActionType } from '@kbn/actions-types'; +import { BASE_ACTION_API_PATH, INTERNAL_BASE_ACTION_API_PATH } from '../../constants'; +import { transformConnectorTypesResponse } from './transform_connector_types_response'; + +export const fetchConnectorTypes = async ({ + http, + featureId, + includeSystemActions = false, +}: { + http: HttpSetup; + featureId?: string; + includeSystemActions?: boolean; +}): Promise => { + const path = includeSystemActions + ? `${INTERNAL_BASE_ACTION_API_PATH}/connector_types` + : `${BASE_ACTION_API_PATH}/connector_types`; + + const res = featureId + ? await http.get[0]>(path, { + query: { + feature_id: featureId, + }, + }) + : await http.get[0]>(path, {}); + return transformConnectorTypesResponse(res); +}; diff --git a/packages/kbn-alerts-ui-shared/src/common/apis/fetch_connector_types/index.ts b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_connector_types/index.ts new file mode 100644 index 0000000000000..9304489dbcbd5 --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_connector_types/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * from './fetch_connector_types'; diff --git a/packages/kbn-alerts-ui-shared/src/common/apis/fetch_connector_types/transform_connector_types_response.test.ts b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_connector_types/transform_connector_types_response.test.ts new file mode 100644 index 0000000000000..dd6ebce579ca5 --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_connector_types/transform_connector_types_response.test.ts @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { transformConnectorTypesResponse } from './transform_connector_types_response'; + +describe('transformConnectorTypesResponse', () => { + test('should transform connector types response', () => { + const result = transformConnectorTypesResponse([ + { + id: 'actionType1Id', + name: 'actionType1', + enabled: true, + enabled_in_config: true, + enabled_in_license: true, + minimum_license_required: 'basic', + supported_feature_ids: ['stackAlerts'], + is_system_action_type: true, + }, + { + id: 'actionType2Id', + name: 'actionType2', + enabled: false, + enabled_in_config: false, + enabled_in_license: false, + minimum_license_required: 'basic', + supported_feature_ids: ['stackAlerts'], + is_system_action_type: false, + }, + ]); + + expect(result).toEqual([ + { + id: 'actionType1Id', + name: 'actionType1', + enabled: true, + enabledInConfig: true, + enabledInLicense: true, + minimumLicenseRequired: 'basic', + supportedFeatureIds: ['stackAlerts'], + isSystemActionType: true, + }, + { + id: 'actionType2Id', + name: 'actionType2', + enabled: false, + enabledInConfig: false, + enabledInLicense: false, + minimumLicenseRequired: 'basic', + supportedFeatureIds: ['stackAlerts'], + isSystemActionType: false, + }, + ]); + }); +}); diff --git a/packages/kbn-alerts-ui-shared/src/common/apis/fetch_connector_types/transform_connector_types_response.ts b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_connector_types/transform_connector_types_response.ts new file mode 100644 index 0000000000000..27326b220187a --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_connector_types/transform_connector_types_response.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { AsApiContract, RewriteRequestCase, ActionType } from '@kbn/actions-types'; + +const transformConnectorType: RewriteRequestCase = ({ + enabled_in_config: enabledInConfig, + enabled_in_license: enabledInLicense, + minimum_license_required: minimumLicenseRequired, + supported_feature_ids: supportedFeatureIds, + is_system_action_type: isSystemActionType, + ...res +}: AsApiContract) => ({ + enabledInConfig, + enabledInLicense, + minimumLicenseRequired, + supportedFeatureIds, + isSystemActionType, + ...res, +}); + +export const transformConnectorTypesResponse = ( + results: Array> +): ActionType[] => { + return results.map((item) => transformConnectorType(item)); +}; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/action_connector_api/connectors.test.ts b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_connectors/fetch_connectors.test.ts similarity index 83% rename from x-pack/plugins/triggers_actions_ui/public/application/lib/action_connector_api/connectors.test.ts rename to packages/kbn-alerts-ui-shared/src/common/apis/fetch_connectors/fetch_connectors.test.ts index 3633e4234e32c..4a9b180dbae96 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/action_connector_api/connectors.test.ts +++ b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_connectors/fetch_connectors.test.ts @@ -1,19 +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. + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. */ import { httpServiceMock } from '@kbn/core/public/mocks'; -import { ActionConnectorProps } from '../../../types'; -import { loadAllActions } from '.'; +import { ActionConnectorProps } from '../../types'; +import { fetchConnectors } from './fetch_connectors'; const http = httpServiceMock.createStartContract(); beforeEach(() => jest.resetAllMocks()); -describe('loadAllActions', () => { +describe('fetchConnectors', () => { test('should call getAll actions API', async () => { const apiResponseValue = [ { @@ -47,7 +48,7 @@ describe('loadAllActions', () => { http.get.mockResolvedValueOnce(apiResponseValue); - const result = await loadAllActions({ http }); + const result = await fetchConnectors({ http }); expect(result).toEqual(resolvedValue); expect(http.get.mock.calls[0]).toMatchInlineSnapshot(` @@ -90,7 +91,7 @@ describe('loadAllActions', () => { http.get.mockResolvedValueOnce(apiResponseValue); - const result = await loadAllActions({ http, includeSystemActions: true }); + const result = await fetchConnectors({ http, includeSystemActions: true }); expect(result).toEqual(resolvedValue); expect(http.get.mock.calls[0]).toMatchInlineSnapshot(` diff --git a/packages/kbn-alerts-ui-shared/src/common/apis/fetch_connectors/fetch_connectors.ts b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_connectors/fetch_connectors.ts new file mode 100644 index 0000000000000..50dbe40523cf8 --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_connectors/fetch_connectors.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { HttpSetup } from '@kbn/core/public'; +import { ActionConnector } from '../../types'; +import { transformConnectorResponse } from './transform_connectors_response'; +import { BASE_ACTION_API_PATH, INTERNAL_BASE_ACTION_API_PATH } from '../../constants'; + +export async function fetchConnectors({ + http, + includeSystemActions = false, +}: { + http: HttpSetup; + includeSystemActions?: boolean; +}): Promise { + // Use the internal get_all_system route to load all action connectors and preconfigured system action connectors + // This is necessary to load UI elements that require system action connectors, even if they're not selectable and + // editable from the connector selection UI like a normal action connector. + const path = includeSystemActions + ? `${INTERNAL_BASE_ACTION_API_PATH}/connectors` + : `${BASE_ACTION_API_PATH}/connectors`; + + const res = await http.get[0]>(path); + + return transformConnectorResponse(res) as ActionConnector[]; +} diff --git a/packages/kbn-alerts-ui-shared/src/common/apis/fetch_connectors/index.ts b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_connectors/index.ts new file mode 100644 index 0000000000000..3c8902ebfbd3c --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_connectors/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * from './fetch_connectors'; diff --git a/packages/kbn-alerts-ui-shared/src/common/apis/fetch_connectors/transform_connectors_response.test.ts b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_connectors/transform_connectors_response.test.ts new file mode 100644 index 0000000000000..5b32a80e11322 --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_connectors/transform_connectors_response.test.ts @@ -0,0 +1,67 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { transformConnectorResponse } from './transform_connectors_response'; + +describe('transformConnectorsResponse', () => { + test('should transform connectors response', () => { + const result = transformConnectorResponse([ + { + id: 'test-connector-1', + name: 'Test-1', + connector_type_id: 'test-1', + is_preconfigured: false, + is_deprecated: false, + is_missing_secrets: false, + is_system_action: false, + referenced_by_count: 0, + secrets: {}, + config: {}, + }, + { + id: 'test-connector-2', + name: 'Test-2', + connector_type_id: 'test-2', + is_preconfigured: true, + is_deprecated: true, + is_missing_secrets: true, + is_system_action: true, + referenced_by_count: 0, + secrets: {}, + config: {}, + }, + ]); + + expect(result).toEqual([ + { + actionTypeId: 'test-1', + config: {}, + id: 'test-connector-1', + isDeprecated: false, + isMissingSecrets: false, + isPreconfigured: false, + isSystemAction: false, + name: 'Test-1', + referencedByCount: 0, + secrets: {}, + }, + { + actionTypeId: 'test-2', + config: {}, + id: 'test-connector-2', + isDeprecated: true, + isMissingSecrets: true, + isPreconfigured: true, + isSystemAction: true, + name: 'Test-2', + referencedByCount: 0, + secrets: {}, + }, + ]); + }); +}); diff --git a/packages/kbn-alerts-ui-shared/src/common/apis/fetch_connectors/transform_connectors_response.ts b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_connectors/transform_connectors_response.ts new file mode 100644 index 0000000000000..4e5ce23ef903c --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_connectors/transform_connectors_response.ts @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { AsApiContract, RewriteRequestCase } from '@kbn/actions-types'; +import { ActionConnectorProps } from '../../types'; + +export const transformConnectorResponse = ( + results: Array< + AsApiContract, Record>> + > +): Array, Record>> => { + return results.map((item) => transformConnector(item)); +}; + +const transformConnector: RewriteRequestCase< + ActionConnectorProps, Record> +> = ({ + connector_type_id: actionTypeId, + is_preconfigured: isPreconfigured, + is_deprecated: isDeprecated, + referenced_by_count: referencedByCount, + is_missing_secrets: isMissingSecrets, + is_system_action: isSystemAction, + ...res +}) => ({ + actionTypeId, + isPreconfigured, + isDeprecated, + referencedByCount, + isMissingSecrets, + isSystemAction, + ...res, +}); diff --git a/packages/kbn-alerts-ui-shared/src/common/apis/fetch_rule_type_aad_template_fields/fetch_rule_type_aad_template_fields.test.ts b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_rule_type_aad_template_fields/fetch_rule_type_aad_template_fields.test.ts new file mode 100644 index 0000000000000..f930c79f31acc --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_rule_type_aad_template_fields/fetch_rule_type_aad_template_fields.test.ts @@ -0,0 +1,67 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { httpServiceMock } from '@kbn/core/public/mocks'; +import { + fetchRuleTypeAadTemplateFields, + getDescription, +} from './fetch_rule_type_aad_template_fields'; +import { EcsMetadata } from '@kbn/alerts-as-data-utils/src/field_maps/types'; + +const http = httpServiceMock.createStartContract(); + +describe('fetchRuleTypeAadTemplateFields', () => { + test('should call aad fields endpoint with the correct params', async () => { + http.get.mockResolvedValueOnce(['mockData']); + + const result = await fetchRuleTypeAadTemplateFields({ + http, + ruleTypeId: 'test-rule-type-id', + }); + + expect(result).toEqual(['mockData']); + expect(http.get.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/internal/rac/alerts/aad_fields", + Object { + "query": Object { + "ruleTypeId": "test-rule-type-id", + }, + }, + ] + `); + }); +}); + +describe('getDescription', () => { + test('should return ecsField description', () => { + const result = getDescription('test-field-name', { + 'test-field-name': { + description: 'this is the test field description', + } as EcsMetadata, + }); + + expect(result).toEqual('this is the test field description'); + }); + + test('should return empty string if ecsField does not have a description', () => { + const result = getDescription('test-field-name', {}); + + expect(result).toEqual(''); + }); + + test('should truncate field name if it contains kibana.alert', () => { + const result = getDescription('kibana.alert.test-field-name', { + 'test-field-name': { + description: 'this is the test field description', + } as EcsMetadata, + }); + + expect(result).toEqual('this is the test field description'); + }); +}); diff --git a/packages/kbn-alerts-ui-shared/src/common/apis/fetch_rule_type_aad_template_fields/fetch_rule_type_aad_template_fields.ts b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_rule_type_aad_template_fields/fetch_rule_type_aad_template_fields.ts new file mode 100644 index 0000000000000..6bba409bbbb4e --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_rule_type_aad_template_fields/fetch_rule_type_aad_template_fields.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { isEmpty } from 'lodash'; +import type { EcsMetadata } from '@kbn/alerts-as-data-utils/src/field_maps/types'; +import type { HttpStart } from '@kbn/core-http-browser'; +import { DataViewField } from '@kbn/data-views-plugin/common'; +import { BASE_RAC_ALERTS_API_PATH, EMPTY_AAD_FIELDS } from '../../constants'; + +export const getDescription = (fieldName: string, ecsFlat: Record) => { + let ecsField = ecsFlat[fieldName]; + if (isEmpty(ecsField?.description ?? '') && fieldName.includes('kibana.alert.')) { + ecsField = ecsFlat[fieldName.replace('kibana.alert.', '')]; + } + return ecsField?.description ?? ''; +}; + +export const fetchRuleTypeAadTemplateFields = async ({ + http, + ruleTypeId, +}: { + http: HttpStart; + ruleTypeId?: string; +}): Promise => { + if (!ruleTypeId) return EMPTY_AAD_FIELDS; + const fields = await http.get(`${BASE_RAC_ALERTS_API_PATH}/aad_fields`, { + query: { ruleTypeId }, + }); + + return fields; +}; diff --git a/packages/kbn-alerts-ui-shared/src/common/apis/fetch_rule_type_aad_template_fields/index.ts b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_rule_type_aad_template_fields/index.ts new file mode 100644 index 0000000000000..ba909a4dc92ce --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/common/apis/fetch_rule_type_aad_template_fields/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * from './fetch_rule_type_aad_template_fields'; diff --git a/packages/kbn-alerts-ui-shared/src/common/apis/index.ts b/packages/kbn-alerts-ui-shared/src/common/apis/index.ts index 8d7e06d6d6f41..95c8c9632146b 100644 --- a/packages/kbn-alerts-ui-shared/src/common/apis/index.ts +++ b/packages/kbn-alerts-ui-shared/src/common/apis/index.ts @@ -12,3 +12,6 @@ export * from './fetch_ui_config'; export * from './create_rule'; export * from './update_rule'; export * from './resolve_rule'; +export * from './fetch_connectors'; +export * from './fetch_connector_types'; +export * from './fetch_rule_type_aad_template_fields'; diff --git a/x-pack/plugins/triggers_actions_ui/public/common/constants/i18n_weekdays.ts b/packages/kbn-alerts-ui-shared/src/common/constants/i18n_weekdays.ts similarity index 65% rename from x-pack/plugins/triggers_actions_ui/public/common/constants/i18n_weekdays.ts rename to packages/kbn-alerts-ui-shared/src/common/constants/i18n_weekdays.ts index b40004426bc29..792e5538a252c 100644 --- a/x-pack/plugins/triggers_actions_ui/public/common/constants/i18n_weekdays.ts +++ b/packages/kbn-alerts-ui-shared/src/common/constants/i18n_weekdays.ts @@ -1,10 +1,12 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. */ -import { ISO_WEEKDAYS } from '@kbn/alerting-plugin/common'; + +import { ISO_WEEKDAYS } from '@kbn/alerting-types'; import moment from 'moment'; export const I18N_WEEKDAY_OPTIONS = ISO_WEEKDAYS.map((n) => ({ diff --git a/packages/kbn-alerts-ui-shared/src/common/constants/index.ts b/packages/kbn-alerts-ui-shared/src/common/constants/index.ts new file mode 100644 index 0000000000000..c3619df3ef99d --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/common/constants/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * from './i18n_weekdays'; +export * from './routes'; diff --git a/packages/kbn-alerts-ui-shared/src/common/constants.ts b/packages/kbn-alerts-ui-shared/src/common/constants/routes.ts similarity index 87% rename from packages/kbn-alerts-ui-shared/src/common/constants.ts rename to packages/kbn-alerts-ui-shared/src/common/constants/routes.ts index ccc59f18d299c..c741192249f9e 100644 --- a/packages/kbn-alerts-ui-shared/src/common/constants.ts +++ b/packages/kbn-alerts-ui-shared/src/common/constants/routes.ts @@ -14,3 +14,5 @@ export const INTERNAL_BASE_ALERTING_API_PATH = '/internal/alerting'; export const BASE_RAC_ALERTS_API_PATH = '/internal/rac/alerts'; export const EMPTY_AAD_FIELDS: DataViewField[] = []; export const BASE_TRIGGERS_ACTIONS_UI_API_PATH = '/internal/triggers_actions_ui'; +export const BASE_ACTION_API_PATH = '/api/actions'; +export const INTERNAL_BASE_ACTION_API_PATH = '/internal/actions'; diff --git a/packages/kbn-alerts-ui-shared/src/common/hooks/use_load_connector_types.test.tsx b/packages/kbn-alerts-ui-shared/src/common/hooks/use_load_connector_types.test.tsx new file mode 100644 index 0000000000000..2cec2afba67d4 --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/common/hooks/use_load_connector_types.test.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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { renderHook } from '@testing-library/react-hooks/dom'; +import { waitFor } from '@testing-library/react'; +import { httpServiceMock } from '@kbn/core/public/mocks'; + +import { useLoadActionTypes } from './use_load_connector_types'; + +const queryClient = new QueryClient(); + +const wrapper = ({ children }: { children: Node }) => ( + {children} +); + +const http = httpServiceMock.createStartContract(); + +describe('useLoadConnectorTypes', () => { + beforeEach(() => { + http.get.mockResolvedValue([ + { + id: 'test', + name: 'Test', + enabled: true, + enabled_in_config: true, + enabled_in_license: true, + supported_feature_ids: ['alerting'], + minimum_license_required: 'basic', + is_system_action_type: false, + }, + ]); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test('should call API endpoint with the correct parameters', async () => { + const { result } = renderHook( + () => + useLoadActionTypes({ + http, + includeSystemActions: true, + }), + { wrapper } + ); + + await waitFor(() => { + return expect(result.current.isInitialLoading).toEqual(false); + }); + + expect(result.current.data).toEqual([ + { + enabled: true, + enabledInConfig: true, + enabledInLicense: true, + id: 'test', + isSystemActionType: false, + minimumLicenseRequired: 'basic', + name: 'Test', + supportedFeatureIds: ['alerting'], + }, + ]); + }); + + test('should call the correct endpoint if system actions is true', async () => { + const { result } = renderHook( + () => + useLoadActionTypes({ + http, + includeSystemActions: true, + }), + { wrapper } + ); + + await waitFor(() => { + return expect(result.current.isInitialLoading).toEqual(false); + }); + + expect(http.get).toHaveBeenCalledWith('/internal/actions/connector_types', {}); + }); + + test('should call the correct endpoint if system actions is false', async () => { + const { result } = renderHook( + () => + useLoadActionTypes({ + http, + includeSystemActions: false, + }), + { wrapper } + ); + + await waitFor(() => { + return expect(result.current.isInitialLoading).toEqual(false); + }); + + expect(http.get).toHaveBeenCalledWith('/api/actions/connector_types', {}); + }); +}); diff --git a/packages/kbn-alerts-ui-shared/src/common/hooks/use_load_connector_types.ts b/packages/kbn-alerts-ui-shared/src/common/hooks/use_load_connector_types.ts new file mode 100644 index 0000000000000..2697f3974f4d2 --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/common/hooks/use_load_connector_types.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { useQuery } from '@tanstack/react-query'; +import type { HttpStart } from '@kbn/core-http-browser'; +import { fetchConnectorTypes } from '../apis'; + +export interface UseLoadActionTypesProps { + http: HttpStart; + includeSystemActions?: boolean; +} + +export const useLoadActionTypes = (props: UseLoadActionTypesProps) => { + const { http, includeSystemActions } = props; + + const queryFn = () => { + return fetchConnectorTypes({ http, includeSystemActions }); + }; + + const { data, isLoading, isFetching, isInitialLoading } = useQuery({ + queryKey: ['useLoadConnectorTypes', includeSystemActions], + queryFn, + refetchOnWindowFocus: false, + }); + + return { + data, + isInitialLoading, + isLoading: isLoading || isFetching, + }; +}; diff --git a/packages/kbn-alerts-ui-shared/src/common/hooks/use_load_connectors.test.tsx b/packages/kbn-alerts-ui-shared/src/common/hooks/use_load_connectors.test.tsx new file mode 100644 index 0000000000000..ee5205ac59440 --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/common/hooks/use_load_connectors.test.tsx @@ -0,0 +1,110 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { renderHook } from '@testing-library/react-hooks/dom'; +import { waitFor } from '@testing-library/react'; +import { httpServiceMock } from '@kbn/core/public/mocks'; + +import { useLoadConnectors } from './use_load_connectors'; + +const queryClient = new QueryClient(); + +const wrapper = ({ children }: { children: Node }) => ( + {children} +); + +const http = httpServiceMock.createStartContract(); + +describe('useLoadConnectors', () => { + beforeEach(() => { + http.get.mockResolvedValue([ + { + id: 'test-connector', + name: 'Test', + connector_type_id: 'test', + is_preconfigured: false, + is_deprecated: false, + is_missing_secrets: false, + is_system_action: false, + referenced_by_count: 0, + secrets: {}, + config: {}, + }, + ]); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test('should call API endpoint with the correct parameters', async () => { + const { result } = renderHook( + () => + useLoadConnectors({ + http, + includeSystemActions: true, + }), + { wrapper } + ); + + await waitFor(() => { + return expect(result.current.isInitialLoading).toEqual(false); + }); + + expect(result.current.data).toEqual([ + { + actionTypeId: 'test', + config: {}, + id: 'test-connector', + isDeprecated: false, + isMissingSecrets: false, + isPreconfigured: false, + isSystemAction: false, + name: 'Test', + referencedByCount: 0, + secrets: {}, + }, + ]); + }); + + test('should call the correct endpoint if system actions is true', async () => { + const { result } = renderHook( + () => + useLoadConnectors({ + http, + includeSystemActions: true, + }), + { wrapper } + ); + + await waitFor(() => { + return expect(result.current.isInitialLoading).toEqual(false); + }); + + expect(http.get).toHaveBeenCalledWith('/internal/actions/connectors'); + }); + + test('should call the correct endpoint if system actions is false', async () => { + const { result } = renderHook( + () => + useLoadConnectors({ + http, + includeSystemActions: false, + }), + { wrapper } + ); + + await waitFor(() => { + return expect(result.current.isInitialLoading).toEqual(false); + }); + + expect(http.get).toHaveBeenCalledWith('/api/actions/connectors'); + }); +}); diff --git a/packages/kbn-alerts-ui-shared/src/common/hooks/use_load_connectors.ts b/packages/kbn-alerts-ui-shared/src/common/hooks/use_load_connectors.ts new file mode 100644 index 0000000000000..3326c6b29be80 --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/common/hooks/use_load_connectors.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { useQuery } from '@tanstack/react-query'; +import type { HttpStart } from '@kbn/core-http-browser'; +import { fetchConnectors } from '../apis'; + +export interface UseLoadConnectorsProps { + http: HttpStart; + includeSystemActions?: boolean; +} + +export const useLoadConnectors = (props: UseLoadConnectorsProps) => { + const { http, includeSystemActions = false } = props; + + const queryFn = () => { + return fetchConnectors({ http, includeSystemActions }); + }; + + const { data, isLoading, isFetching, isInitialLoading } = useQuery({ + queryKey: ['useLoadConnectors', includeSystemActions], + queryFn, + refetchOnWindowFocus: false, + }); + + return { + data, + isInitialLoading, + isLoading: isLoading || isFetching, + }; +}; diff --git a/packages/kbn-alerts-ui-shared/src/common/hooks/use_load_rule_type_aad_template_fields.test.tsx b/packages/kbn-alerts-ui-shared/src/common/hooks/use_load_rule_type_aad_template_fields.test.tsx new file mode 100644 index 0000000000000..11238ecbef580 --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/common/hooks/use_load_rule_type_aad_template_fields.test.tsx @@ -0,0 +1,72 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { renderHook } from '@testing-library/react-hooks/dom'; +import { waitFor } from '@testing-library/react'; +import { httpServiceMock } from '@kbn/core/public/mocks'; + +import { useLoadRuleTypeAadTemplateField } from './use_load_rule_type_aad_template_fields'; + +const queryClient = new QueryClient(); + +const wrapper = ({ children }: { children: Node }) => ( + {children} +); + +const http = httpServiceMock.createStartContract(); + +describe('useLoadRuleTypeAadTemplateFields', () => { + beforeEach(() => { + http.get.mockResolvedValue([ + { + name: '@timestamp', + deprecated: false, + useWithTripleBracesInTemplates: false, + usesPublicBaseUrl: false, + }, + ]); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test('should call API endpoint with the correct parameters', async () => { + const { result } = renderHook( + () => + useLoadRuleTypeAadTemplateField({ + http, + ruleTypeId: 'ruleTypeId', + enabled: true, + }), + { wrapper } + ); + + await waitFor(() => { + return expect(result.current.isInitialLoading).toEqual(false); + }); + + expect(http.get).toHaveBeenLastCalledWith('/internal/rac/alerts/aad_fields', { + query: { ruleTypeId: 'ruleTypeId' }, + }); + + expect(result.current.data).toMatchInlineSnapshot(` + Array [ + Object { + "description": "Date/time when the event originated. + This is the date/time extracted from the event, typically representing when the event was generated by the source. + If the event source has no original timestamp, this value is typically populated by the first time the event was received by the pipeline. + Required field for all events.", + "name": "@timestamp", + }, + ] + `); + }); +}); diff --git a/packages/kbn-alerts-ui-shared/src/common/hooks/use_load_rule_type_aad_template_fields.ts b/packages/kbn-alerts-ui-shared/src/common/hooks/use_load_rule_type_aad_template_fields.ts new file mode 100644 index 0000000000000..1d52134c53015 --- /dev/null +++ b/packages/kbn-alerts-ui-shared/src/common/hooks/use_load_rule_type_aad_template_fields.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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { EcsFlat } from '@elastic/ecs'; +import { ActionVariable } from '@kbn/alerting-types'; +import type { HttpStart } from '@kbn/core-http-browser'; +import { useQuery } from '@tanstack/react-query'; +import { fetchRuleTypeAadTemplateFields, getDescription } from '../apis'; + +export interface UseLoadRuleTypeAadTemplateFieldProps { + http: HttpStart; + ruleTypeId: string; + enabled: boolean; +} + +export const useLoadRuleTypeAadTemplateField = (props: UseLoadRuleTypeAadTemplateFieldProps) => { + const { http, ruleTypeId, enabled } = props; + + const queryFn = () => { + return fetchRuleTypeAadTemplateFields({ http, ruleTypeId }); + }; + + const { + data = [], + isLoading, + isFetching, + isInitialLoading, + } = useQuery({ + queryKey: ['useLoadRuleTypeAadTemplateField', ruleTypeId], + queryFn, + select: (dataViewFields) => { + return dataViewFields.map((d) => ({ + name: d.name, + description: getDescription(d.name, EcsFlat), + })); + }, + refetchOnWindowFocus: false, + enabled, + }); + + return { + data, + isInitialLoading, + isLoading: isLoading || isFetching, + }; +}; diff --git a/packages/kbn-alerts-ui-shared/src/common/hooks/use_rule_aad_fields.ts b/packages/kbn-alerts-ui-shared/src/common/hooks/use_rule_aad_fields.ts index e92d64c8f11b0..6a65d80e02ab9 100644 --- a/packages/kbn-alerts-ui-shared/src/common/hooks/use_rule_aad_fields.ts +++ b/packages/kbn-alerts-ui-shared/src/common/hooks/use_rule_aad_fields.ts @@ -12,7 +12,7 @@ import { i18n } from '@kbn/i18n'; import type { ToastsStart, HttpStart } from '@kbn/core/public'; import type { DataViewField } from '@kbn/data-views-plugin/common'; import { EMPTY_AAD_FIELDS } from '../constants'; -import { fetchAadFields } from '../apis/fetch_aad_fields'; +import { fetchRuleTypeAadTemplateFields } from '../apis'; export interface UseRuleAADFieldsProps { ruleTypeId?: string; @@ -29,7 +29,7 @@ export function useRuleAADFields(props: UseRuleAADFieldsProps): UseRuleAADFields const { ruleTypeId, http, toasts } = props; const queryAadFieldsFn = () => { - return fetchAadFields({ http, ruleTypeId }); + return fetchRuleTypeAadTemplateFields({ http, ruleTypeId }); }; const onErrorFn = () => { diff --git a/packages/kbn-alerts-ui-shared/src/common/types/rule_types.ts b/packages/kbn-alerts-ui-shared/src/common/types/rule_types.ts index c68345cd96c69..fefde257308c6 100644 --- a/packages/kbn-alerts-ui-shared/src/common/types/rule_types.ts +++ b/packages/kbn-alerts-ui-shared/src/common/types/rule_types.ts @@ -24,6 +24,8 @@ import { RuleType } from '@kbn/triggers-actions-ui-types'; import { PublicMethodsOf } from '@kbn/utility-types'; import { TypeRegistry } from '../type_registry'; +export type { SanitizedRuleAction as RuleAction } from '@kbn/alerting-types'; + export type RuleTypeWithDescription = RuleType & { description?: string }; export type RuleTypeIndexWithDescriptions = Map; diff --git a/packages/kbn-alerts-ui-shared/src/rule_form/constants.ts b/packages/kbn-alerts-ui-shared/src/rule_form/constants.ts index fb3235e73df44..6b693333e373b 100644 --- a/packages/kbn-alerts-ui-shared/src/rule_form/constants.ts +++ b/packages/kbn-alerts-ui-shared/src/rule_form/constants.ts @@ -13,12 +13,19 @@ import { RuleCreationValidConsumer, AlertConsumers, } from '@kbn/rule-data-utils'; +import { RuleNotifyWhen } from '@kbn/alerting-types'; import { RuleFormData } from './types'; export const DEFAULT_RULE_INTERVAL = '1m'; export const ALERTING_FEATURE_ID = 'alerts'; +export const DEFAULT_FREQUENCY = { + notifyWhen: RuleNotifyWhen.CHANGE, + throttle: null, + summary: false, +}; + export const GET_DEFAULT_FORM_DATA = ({ ruleTypeId, name, diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_alerts_filter_timeframe.test.tsx b/packages/kbn-alerts-ui-shared/src/rule_form/rule_actions/rule_actions_alerts_filter_timeframe.test.tsx similarity index 83% rename from x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_alerts_filter_timeframe.test.tsx rename to packages/kbn-alerts-ui-shared/src/rule_form/rule_actions/rule_actions_alerts_filter_timeframe.test.tsx index ea666d1f2dd3e..ab50c62f70117 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_alerts_filter_timeframe.test.tsx +++ b/packages/kbn-alerts-ui-shared/src/rule_form/rule_actions/rule_actions_alerts_filter_timeframe.test.tsx @@ -1,25 +1,33 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. */ +import { Moment } from 'moment'; import React from 'react'; -import { mountWithIntl, nextTick } from '@kbn/test-jest-helpers'; import { act } from 'react-dom/test-utils'; -import { ActionAlertsFilterTimeframe } from './action_alerts_filter_timeframe'; -import { AlertsFilterTimeframe } from '@kbn/alerting-plugin/common'; -import { Moment } from 'moment'; - -jest.mock('@kbn/kibana-react-plugin/public/ui_settings/use_ui_setting', () => ({ - useUiSetting: jest.fn().mockImplementation((_, defaultValue) => defaultValue), -})); +import { mountWithIntl, nextTick } from '@kbn/test-jest-helpers'; +import type { SettingsStart } from '@kbn/core-ui-settings-browser'; +import { RuleActionsAlertsFilterTimeframe } from './rule_actions_alerts_filter_timeframe'; +import { AlertsFilterTimeframe } from '@kbn/alerting-types'; -describe('action_alerts_filter_timeframe', () => { +describe('ruleActionsAlertsFilterTimeframe', () => { async function setup(timeframe?: AlertsFilterTimeframe) { const wrapper = mountWithIntl( - {}} /> + defaultValue), + }, + } as unknown as SettingsStart + } + onChange={() => {}} + /> ); // Wait for active space to resolve before requesting the component to update diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_alerts_filter_timeframe.tsx b/packages/kbn-alerts-ui-shared/src/rule_form/rule_actions/rule_actions_alerts_filter_timeframe.tsx similarity index 78% rename from x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_alerts_filter_timeframe.tsx rename to packages/kbn-alerts-ui-shared/src/rule_form/rule_actions/rule_actions_alerts_filter_timeframe.tsx index 9467feaabd676..5b4580caa7ebf 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_alerts_filter_timeframe.tsx +++ b/packages/kbn-alerts-ui-shared/src/rule_form/rule_actions/rule_actions_alerts_filter_timeframe.tsx @@ -1,13 +1,14 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. */ import moment, { Moment } from 'moment'; import React, { useState, useCallback, useMemo, useEffect } from 'react'; -import { useUiSetting } from '@kbn/kibana-react-plugin/public'; +import type { SettingsStart } from '@kbn/core-ui-settings-browser'; import { i18n } from '@kbn/i18n'; import { EuiFlexGroup, @@ -20,18 +21,19 @@ import { EuiComboBox, } from '@elastic/eui'; import deepEqual from 'fast-deep-equal'; -import { AlertsFilterTimeframe, ISO_WEEKDAYS, IsoWeekday } from '@kbn/alerting-plugin/common'; -import { I18N_WEEKDAY_OPTIONS_DDD } from '../../../common/constants'; +import { ISO_WEEKDAYS, type IsoWeekday, type AlertsFilterTimeframe } from '@kbn/alerting-types'; +import { I18N_WEEKDAY_OPTIONS_DDD } from '../../common/constants'; -interface ActionAlertsFilterTimeframeProps { +interface RuleActionsAlertsFilterTimeframeProps { state?: AlertsFilterTimeframe; + settings: SettingsStart; onChange: (update?: AlertsFilterTimeframe) => void; } const TIMEZONE_OPTIONS = moment.tz?.names().map((n) => ({ label: n })) ?? [{ label: 'UTC' }]; -const useSortedWeekdayOptions = () => { - const kibanaDow: string = useUiSetting('dateFormat:dow'); +const useSortedWeekdayOptions = (settings: SettingsStart) => { + const kibanaDow: string = settings.client.get('dateFormat:dow'); const startDow = kibanaDow ?? 'Sunday'; const startDowIndex = I18N_WEEKDAY_OPTIONS_DDD.findIndex((o) => o.label.startsWith(startDow)); return [ @@ -40,14 +42,20 @@ const useSortedWeekdayOptions = () => { ]; }; -const useDefaultTimezone = () => { - const kibanaTz: string = useUiSetting('dateFormat:tz'); +const useDefaultTimezone = (settings: SettingsStart) => { + const kibanaTz: string = settings.client.get('dateFormat:tz'); if (!kibanaTz || kibanaTz === 'Browser') return moment.tz?.guess() ?? 'UTC'; return kibanaTz; }; -const useTimeframe = (initialTimeframe?: AlertsFilterTimeframe) => { - const timezone = useDefaultTimezone(); +const useTimeframe = ({ + initialTimeframe, + settings, +}: { + initialTimeframe?: AlertsFilterTimeframe; + settings: SettingsStart; +}) => { + const timezone = useDefaultTimezone(settings); const DEFAULT_TIMEFRAME = { days: [], timezone, @@ -58,25 +66,29 @@ const useTimeframe = (initialTimeframe?: AlertsFilterTimeframe) => { }; return useState(initialTimeframe || DEFAULT_TIMEFRAME); }; -const useTimeFormat = () => { - const dateFormatScaled: Array<[string, string]> = useUiSetting('dateFormat:scaled') ?? [ +const useTimeFormat = (settings: SettingsStart) => { + const dateFormatScaled: Array<[string, string]> = settings.client.get('dateFormat:scaled') ?? [ ['PT1M', 'HH:mm'], ]; const [, PT1M] = dateFormatScaled.find(([key]) => key === 'PT1M') ?? ['', 'HH:mm']; return PT1M; }; -export const ActionAlertsFilterTimeframe: React.FC = ({ +export const RuleActionsAlertsFilterTimeframe: React.FC = ({ state, + settings, onChange, }) => { - const timeFormat = useTimeFormat(); - const [timeframe, setTimeframe] = useTimeframe(state); + const timeFormat = useTimeFormat(settings); + const [timeframe, setTimeframe] = useTimeframe({ + initialTimeframe: state, + settings, + }); const [selectedTimezone, setSelectedTimezone] = useState([{ label: timeframe.timezone }]); const timeframeEnabled = useMemo(() => Boolean(state), [state]); - const weekdayOptions = useSortedWeekdayOptions(); + const weekdayOptions = useSortedWeekdayOptions(settings); useEffect(() => { const nextState = timeframeEnabled ? timeframe : undefined; @@ -144,7 +156,7 @@ export const ActionAlertsFilterTimeframe: React.FC { +describe('ruleActionsNotifyWhen', () => { async function setup( - frequency: SanitizedRuleAction['frequency'] = DEFAULT_FREQUENCY, + frequency: RuleAction['frequency'] = DEFAULT_FREQUENCY, hasAlertsMappings: boolean = true ) { const wrapper = mountWithIntl( - ; +} export const NOTIFY_WHEN_OPTIONS: NotifyWhenSelectOptions[] = [ { @@ -37,26 +45,23 @@ export const NOTIFY_WHEN_OPTIONS: NotifyWhenSelectOptions[] = [ isForEachAlertOption: true, value: { value: 'onActionGroupChange', - inputDisplay: i18n.translate( - 'xpack.triggersActionsUI.sections.ruleForm.ruleNotifyWhen.onActionGroupChange.display', - { - defaultMessage: 'On status changes', - } - ), + inputDisplay: i18n.translate('alertsUIShared.ruleForm.onActionGroupChange.display', { + defaultMessage: 'On status changes', + }), 'data-test-subj': 'onActionGroupChange', dropdownDisplay: ( <>

@@ -69,26 +74,23 @@ export const NOTIFY_WHEN_OPTIONS: NotifyWhenSelectOptions[] = [ isForEachAlertOption: true, value: { value: 'onActiveAlert', - inputDisplay: i18n.translate( - 'xpack.triggersActionsUI.sections.ruleForm.ruleNotifyWhen.onActiveAlert.display', - { - defaultMessage: 'On check intervals', - } - ), + inputDisplay: i18n.translate('alertsUIShared.ruleForm.onActiveAlert.display', { + defaultMessage: 'On check intervals', + }), 'data-test-subj': 'onActiveAlert', dropdownDisplay: ( <>

@@ -101,26 +103,23 @@ export const NOTIFY_WHEN_OPTIONS: NotifyWhenSelectOptions[] = [ isForEachAlertOption: true, value: { value: 'onThrottleInterval', - inputDisplay: i18n.translate( - 'xpack.triggersActionsUI.sections.ruleForm.ruleNotifyWhen.onThrottleInterval.display', - { - defaultMessage: 'On custom action intervals', - } - ), + inputDisplay: i18n.translate('alertsUIShared.ruleForm.onThrottleInterval.display', { + defaultMessage: 'On custom action intervals', + }), 'data-test-subj': 'onThrottleInterval', dropdownDisplay: ( <>

@@ -130,7 +129,7 @@ export const NOTIFY_WHEN_OPTIONS: NotifyWhenSelectOptions[] = [ }, ]; -interface ActionNotifyWhenProps { +interface RuleActionsNotifyWhenProps { frequency: RuleAction['frequency']; throttle: number | null; throttleUnit: string; @@ -144,7 +143,7 @@ interface ActionNotifyWhenProps { defaultNotifyWhenValue?: RuleNotifyWhenType; } -export const ActionNotifyWhen = ({ +export const RuleActionsNotifyWhen = ({ hasAlertsMappings, frequency = DEFAULT_FREQUENCY, throttle, @@ -156,7 +155,7 @@ export const ActionNotifyWhen = ({ showMinimumThrottleUnitWarning, notifyWhenSelectOptions = NOTIFY_WHEN_OPTIONS, defaultNotifyWhenValue = DEFAULT_FREQUENCY.notifyWhen, -}: ActionNotifyWhenProps) => { +}: RuleActionsNotifyWhenProps) => { const [showCustomThrottleOpts, setShowCustomThrottleOpts] = useState(false); const [notifyWhenValue, setNotifyWhenValue] = useState(defaultNotifyWhenValue); @@ -288,7 +287,7 @@ export const ActionNotifyWhen = ({ anchorPosition="downLeft" aria-label={frequency.summary ? SUMMARY_OF_ALERTS : FOR_EACH_ALERT} aria-roledescription={i18n.translate( - 'xpack.triggersActionsUI.sections.ruleForm.actionNotifyWhen.summaryOrRulePerSelectRoleDescription', + 'alertsUIShared.ruleActionsNotifyWhen.summaryOrRulePerSelectRoleDescription', { defaultMessage: 'Action frequency type select' } )} button={ @@ -309,10 +308,9 @@ export const ActionNotifyWhen = ({ return ( @@ -338,7 +336,7 @@ export const ActionNotifyWhen = ({ name="throttle" data-test-subj="throttleInput" prepend={i18n.translate( - 'xpack.triggersActionsUI.sections.ruleForm.frequencyNotifyWhen.label', + 'alertsUIShared.ruleActionsNotifyWhen.frequencyNotifyWhen.label', { defaultMessage: 'Run every', } @@ -374,7 +372,7 @@ export const ActionNotifyWhen = ({ {i18n.translate( - 'xpack.triggersActionsUI.sections.actionTypeForm.notifyWhenThrottleWarning', + 'alertsUIShared.ruleActionsNotifyWhen.notifyWhenThrottleWarning', { defaultMessage: "Custom action intervals cannot be shorter than the rule's check interval", @@ -391,11 +389,9 @@ export const ActionNotifyWhen = ({ ); }; -const FOR_EACH_ALERT = i18n.translate( - 'xpack.triggersActionsUI.sections.ruleForm.actionNotifyWhen.forEachOption', - { defaultMessage: 'For each alert' } -); -const SUMMARY_OF_ALERTS = i18n.translate( - 'xpack.triggersActionsUI.sections.ruleForm.actionNotifyWhen.summaryOption', - { defaultMessage: 'Summary of alerts' } -); +const FOR_EACH_ALERT = i18n.translate('alertsUIShared.ruleActionsNotifyWhen.forEachOption', { + defaultMessage: 'For each alert', +}); +const SUMMARY_OF_ALERTS = i18n.translate('alertsUIShared.ruleActionsNotifyWhen.summaryOption', { + defaultMessage: 'Summary of alerts', +}); diff --git a/packages/kbn-alerts-ui-shared/tsconfig.json b/packages/kbn-alerts-ui-shared/tsconfig.json index 7fe9d16ad314e..37cc6b12bcea8 100644 --- a/packages/kbn-alerts-ui-shared/tsconfig.json +++ b/packages/kbn-alerts-ui-shared/tsconfig.json @@ -43,5 +43,8 @@ "@kbn/react-kibana-mount", "@kbn/core-i18n-browser", "@kbn/core-theme-browser", + "@kbn/alerts-as-data-utils", + "@kbn/test-jest-helpers", + "@kbn/core-ui-settings-browser", ] } diff --git a/packages/kbn-avc-banner/README.md b/packages/kbn-avc-banner/README.md new file mode 100644 index 0000000000000..3a5ea8c089a4a --- /dev/null +++ b/packages/kbn-avc-banner/README.md @@ -0,0 +1,3 @@ +# @kbn/avc-banner + +`@kbn/avc-banner` is the callout component to showcase the AVC 2024 results Elastic Security recently received for our native Endpoint and encourage users to install Elastic Defend/Endpoint. This package should be delted at EOY 2024. \ No newline at end of file diff --git a/packages/kbn-avc-banner/index.ts b/packages/kbn-avc-banner/index.ts new file mode 100644 index 0000000000000..de0577ee3ed83 --- /dev/null +++ b/packages/kbn-avc-banner/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * from './src'; diff --git a/packages/kbn-avc-banner/jest.config.js b/packages/kbn-avc-banner/jest.config.js new file mode 100644 index 0000000000000..8886c66ec80e7 --- /dev/null +++ b/packages/kbn-avc-banner/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../..', + roots: ['/packages/kbn-avc-banner'], +}; diff --git a/packages/kbn-avc-banner/kibana.jsonc b/packages/kbn-avc-banner/kibana.jsonc new file mode 100644 index 0000000000000..51269b1b2e76b --- /dev/null +++ b/packages/kbn-avc-banner/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-browser", + "id": "@kbn/avc-banner", + "owner": "@elastic/security-defend-workflows" +} diff --git a/packages/kbn-avc-banner/package.json b/packages/kbn-avc-banner/package.json new file mode 100644 index 0000000000000..f01617945592d --- /dev/null +++ b/packages/kbn-avc-banner/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/avc-banner", + "private": true, + "version": "1.0.0", + "license": "SSPL-1.0 OR Elastic License 2.0" +} \ No newline at end of file diff --git a/packages/kbn-avc-banner/src/avc_banner_background.svg b/packages/kbn-avc-banner/src/avc_banner_background.svg new file mode 100644 index 0000000000000..57b0f91a419e9 --- /dev/null +++ b/packages/kbn-avc-banner/src/avc_banner_background.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/kbn-avc-banner/src/custom.d.ts b/packages/kbn-avc-banner/src/custom.d.ts new file mode 100644 index 0000000000000..9169166fe7af9 --- /dev/null +++ b/packages/kbn-avc-banner/src/custom.d.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +declare module '*.svg' { + const content: string; + // eslint-disable-next-line import/no-default-export + export default content; +} diff --git a/x-pack/plugins/security_solution/public/common/components/avc_banner/avc_results_banner_2024.tsx b/packages/kbn-avc-banner/src/index.tsx similarity index 73% rename from x-pack/plugins/security_solution/public/common/components/avc_banner/avc_results_banner_2024.tsx rename to packages/kbn-avc-banner/src/index.tsx index 0c73af1ef4861..54ded0bfdd49d 100644 --- a/x-pack/plugins/security_solution/public/common/components/avc_banner/avc_results_banner_2024.tsx +++ b/packages/kbn-avc-banner/src/index.tsx @@ -1,8 +1,9 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. */ import React from 'react'; @@ -10,13 +11,13 @@ import { css } from '@emotion/css'; import { i18n } from '@kbn/i18n'; import { EuiButton, EuiCallOut, EuiSpacer, useEuiTheme } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import { useKibana } from '../../lib/kibana'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; import avcBannerBackground from './avc_banner_background.svg'; export const AVCResultsBanner2024: React.FC<{ onDismiss: () => void }> = ({ onDismiss }) => { const { docLinks } = useKibana().services; const { euiTheme } = useEuiTheme(); - const bannerTitle = i18n.translate('xpack.securitySolution.common.avcResultsBanner.title', { + const bannerTitle = i18n.translate('avcBanner.title', { defaultMessage: '100% protection with zero false positives.', }); @@ -38,20 +39,18 @@ export const AVCResultsBanner2024: React.FC<{ onDismiss: () => void }> = ({ onDi data-test-subj="avcResultsBanner" > - + ); diff --git a/packages/kbn-avc-banner/tsconfig.json b/packages/kbn-avc-banner/tsconfig.json new file mode 100644 index 0000000000000..b75e84d57cf72 --- /dev/null +++ b/packages/kbn-avc-banner/tsconfig.json @@ -0,0 +1,23 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node", + "react" + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + "@kbn/i18n", + "@kbn/i18n-react", + "@kbn/kibana-react-plugin", + ] +} diff --git a/packages/kbn-check-mappings-update-cli/current_fields.json b/packages/kbn-check-mappings-update-cli/current_fields.json index 31a4b111b69d0..1d62104fac177 100644 --- a/packages/kbn-check-mappings-update-cli/current_fields.json +++ b/packages/kbn-check-mappings-update-cli/current_fields.json @@ -107,6 +107,10 @@ "timestamp" ], "application_usage_totals": [], + "background-task-node": [ + "id", + "last_seen" + ], "canvas-element": [ "@created", "@timestamp", diff --git a/packages/kbn-check-mappings-update-cli/current_mappings.json b/packages/kbn-check-mappings-update-cli/current_mappings.json index 6a9e57fa1a05b..93633a1e05824 100644 --- a/packages/kbn-check-mappings-update-cli/current_mappings.json +++ b/packages/kbn-check-mappings-update-cli/current_mappings.json @@ -348,6 +348,17 @@ "dynamic": false, "properties": {} }, + "background-task-node": { + "dynamic": false, + "properties": { + "id": { + "type": "keyword" + }, + "last_seen": { + "type": "date" + } + } + }, "canvas-element": { "dynamic": false, "properties": { diff --git a/packages/kbn-discover-utils/index.ts b/packages/kbn-discover-utils/index.ts index 795dd3318702a..8194b8ddfc3a3 100644 --- a/packages/kbn-discover-utils/index.ts +++ b/packages/kbn-discover-utils/index.ts @@ -47,6 +47,7 @@ export { getLogLevelCoalescedValue, getLogLevelCoalescedValueLabel, LogLevelCoalescedValue, + LogLevelBadge, } from './src'; export type { LogsContextService } from './src'; diff --git a/packages/kbn-discover-utils/src/__mocks__/data_view.ts b/packages/kbn-discover-utils/src/__mocks__/data_view.ts index 99d05640d270b..1f95990e3e371 100644 --- a/packages/kbn-discover-utils/src/__mocks__/data_view.ts +++ b/packages/kbn-discover-utils/src/__mocks__/data_view.ts @@ -126,6 +126,7 @@ export const buildDataViewMock = ({ return dataViewFields.find((field) => field.name === timeFieldName); }, getRuntimeField: () => null, + setFieldCount: jest.fn(), } as unknown as DataView; dataView.isTimeBased = () => !!timeFieldName; diff --git a/packages/kbn-discover-utils/src/data_types/logs/components/index.ts b/packages/kbn-discover-utils/src/data_types/logs/components/index.ts new file mode 100644 index 0000000000000..56b5847f15749 --- /dev/null +++ b/packages/kbn-discover-utils/src/data_types/logs/components/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * from './log_level_badge'; diff --git a/packages/kbn-discover-utils/src/data_types/logs/components/log_level_badge.test.tsx b/packages/kbn-discover-utils/src/data_types/logs/components/log_level_badge.test.tsx new file mode 100644 index 0000000000000..8ce39dde368ad --- /dev/null +++ b/packages/kbn-discover-utils/src/data_types/logs/components/log_level_badge.test.tsx @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { render, screen } from '@testing-library/react'; +import React from 'react'; +import { LogLevelBadge } from './log_level_badge'; + +const renderBadge = (logLevel: string) => { + render( + {logLevel}} + /> + ); +}; + +describe('LogLevelBadge', () => { + it('renders badge with color based on provided logLevel', () => { + renderBadge('info'); + const badge = screen.getByTestId('logLevelBadge-info'); + expect(badge).toBeInTheDocument(); + expect(badge).toHaveTextContent('info'); + expect(getComputedStyle(badge).getPropertyValue('--euiBadgeBackgroundColor')).toEqual( + '#90b0d1' + ); + }); + + it('renders without a badge if logLevel is not recognized', () => { + renderBadge('unknown_level'); + const badge = screen.getByTestId('logLevelBadge-unknown'); + expect(badge).toBeInTheDocument(); + expect(badge).toHaveTextContent('unknown_level'); + expect(getComputedStyle(badge).getPropertyValue('--euiBadgeBackgroundColor')).toEqual(''); + }); +}); diff --git a/packages/kbn-discover-utils/src/data_types/logs/components/log_level_badge.tsx b/packages/kbn-discover-utils/src/data_types/logs/components/log_level_badge.tsx new file mode 100644 index 0000000000000..726867449e25e --- /dev/null +++ b/packages/kbn-discover-utils/src/data_types/logs/components/log_level_badge.tsx @@ -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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React, { ReactElement } from 'react'; +import { EuiBadge, EuiBadgeProps, mathWithUnits, useEuiTheme } from '@elastic/eui'; +import { CSSObject } from '@emotion/react'; +import { euiThemeVars } from '@kbn/ui-theme'; +import { getLogLevelCoalescedValue, getLogLevelColor } from '../utils'; + +const badgeCss: CSSObject = { + maxWidth: mathWithUnits(euiThemeVars.euiSize, (size) => size * 7.5), +}; + +export const LogLevelBadge = ({ + logLevel, + fallback, + 'data-test-subj': dataTestSubj = 'logLevelBadge', + ...badgeProps +}: Omit & { + logLevel: {}; + fallback?: ReactElement; +}) => { + const { euiTheme } = useEuiTheme(); + const coalescedValue = getLogLevelCoalescedValue(logLevel); + const color = coalescedValue ? getLogLevelColor(coalescedValue, euiTheme) : undefined; + const castedBadgeProps = badgeProps as EuiBadgeProps; + + if (!color || !coalescedValue) { + return fallback ? ( + fallback + ) : ( + + {logLevel} + + ); + } + + return ( + + {logLevel} + + ); +}; diff --git a/packages/kbn-discover-utils/src/data_types/logs/index.ts b/packages/kbn-discover-utils/src/data_types/logs/index.ts index f1147d7aa071b..98d581a4085eb 100644 --- a/packages/kbn-discover-utils/src/data_types/logs/index.ts +++ b/packages/kbn-discover-utils/src/data_types/logs/index.ts @@ -7,6 +7,7 @@ */ export * from './types'; +export * from './components'; export * from './utils'; export * from './logs_context_service'; diff --git a/packages/kbn-discover-utils/tsconfig.json b/packages/kbn-discover-utils/tsconfig.json index bbd35127c43fb..de0b747eda555 100644 --- a/packages/kbn-discover-utils/tsconfig.json +++ b/packages/kbn-discover-utils/tsconfig.json @@ -5,7 +5,8 @@ "types": [ "jest", "node", - "react" + "react", + "@testing-library/jest-dom" ] }, "include": [ @@ -23,6 +24,7 @@ "@kbn/field-formats-plugin", "@kbn/field-types", "@kbn/i18n", - "@kbn/core-ui-settings-browser" + "@kbn/core-ui-settings-browser", + "@kbn/ui-theme" ] } diff --git a/packages/kbn-es-types/src/search.ts b/packages/kbn-es-types/src/search.ts index d6cae90f3c019..28cc43771a736 100644 --- a/packages/kbn-es-types/src/search.ts +++ b/packages/kbn-es-types/src/search.ts @@ -691,4 +691,5 @@ export interface ESQLSearchParams { filter?: unknown; locale?: string; dropNullColumns?: boolean; + params?: Array>; } diff --git a/packages/kbn-esql-ast/src/walker/walker.test.ts b/packages/kbn-esql-ast/src/walker/walker.test.ts index ec4e0a8cd701c..1d692feadd0a0 100644 --- a/packages/kbn-esql-ast/src/walker/walker.test.ts +++ b/packages/kbn-esql-ast/src/walker/walker.test.ts @@ -87,6 +87,28 @@ test('can find assignment expression', () => { expect((functions[0].args[0] as any).name).toBe('var0'); }); +test('can collect all params from grouping functions', () => { + const query = + 'ROW x=1, time=2024-07-10 | stats z = avg(x) by bucket(time, 20, ?earliest,?latest)'; + const { ast } = getAstAndSyntaxErrors(query); + const params = Walker.params(ast); + + expect(params).toMatchObject([ + { + type: 'literal', + literalType: 'param', + paramType: 'named', + value: 'earliest', + }, + { + type: 'literal', + literalType: 'param', + paramType: 'named', + value: 'latest', + }, + ]); +}); + describe('Walker.hasFunction()', () => { test('can find assignment expression', () => { const query1 = 'METRICS source bucket(bytes, 1 hour)'; diff --git a/packages/kbn-esql-ast/src/walker/walker.ts b/packages/kbn-esql-ast/src/walker/walker.ts index 70c78b8a533f5..fdb739d49bf60 100644 --- a/packages/kbn-esql-ast/src/walker/walker.ts +++ b/packages/kbn-esql-ast/src/walker/walker.ts @@ -139,6 +139,10 @@ export class Walker { this.walkFunction(node as ESQLFunction); break; } + case 'option': { + this.walkAstItem(node.args); + break; + } case 'column': { options.visitColumn?.(node); break; diff --git a/packages/kbn-esql-utils/index.ts b/packages/kbn-esql-utils/index.ts index e23b81e0ea7f2..2e04d2a5540fc 100644 --- a/packages/kbn-esql-utils/index.ts +++ b/packages/kbn-esql-utils/index.ts @@ -20,6 +20,9 @@ export { getESQLQueryColumns, getESQLQueryColumnsRaw, getESQLResults, + getTimeFieldFromESQLQuery, + getEarliestLatestParams, + hasEarliestLatestParams, TextBasedLanguages, } from './src'; diff --git a/packages/kbn-esql-utils/src/index.ts b/packages/kbn-esql-utils/src/index.ts index 18fc938b5eee5..879e92e3ffa56 100644 --- a/packages/kbn-esql-utils/src/index.ts +++ b/packages/kbn-esql-utils/src/index.ts @@ -15,6 +15,13 @@ export { getLimitFromESQLQuery, removeDropCommandsFromESQLQuery, hasTransformationalCommand, + getTimeFieldFromESQLQuery, } from './utils/query_parsing_helpers'; export { appendToESQLQuery, appendWhereClauseToESQLQuery } from './utils/append_to_query'; -export { getESQLQueryColumns, getESQLQueryColumnsRaw, getESQLResults } from './utils/run_query'; +export { + getESQLQueryColumns, + getESQLQueryColumnsRaw, + getESQLResults, + getEarliestLatestParams, + hasEarliestLatestParams, +} from './utils/run_query'; diff --git a/packages/kbn-esql-utils/src/utils/get_esql_adhoc_dataview.ts b/packages/kbn-esql-utils/src/utils/get_esql_adhoc_dataview.ts index b05dfbe5f5788..1bd805a0ff3b5 100644 --- a/packages/kbn-esql-utils/src/utils/get_esql_adhoc_dataview.ts +++ b/packages/kbn-esql-utils/src/utils/get_esql_adhoc_dataview.ts @@ -7,6 +7,7 @@ */ import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import { ESQL_TYPE } from '@kbn/data-view-utils'; +import { getTimeFieldFromESQLQuery, getIndexPatternFromESQLQuery } from './query_parsing_helpers'; // uses browser sha256 method with fallback if unavailable async function sha256(str: string) { @@ -28,18 +29,22 @@ async function sha256(str: string) { // the same adhoc dataview can be constructed/used. This comes with great advantages such // as solving the problem described here https://github.com/elastic/kibana/issues/168131 export async function getESQLAdHocDataview( - indexPattern: string, + query: string, dataViewsService: DataViewsPublicPluginStart ) { + const timeField = getTimeFieldFromESQLQuery(query); + const indexPattern = getIndexPatternFromESQLQuery(query); const dataView = await dataViewsService.create({ title: indexPattern, type: ESQL_TYPE, id: await sha256(`esql-${indexPattern}`), }); + dataView.timeFieldName = timeField; + // If the indexPattern is empty string means that the user used either the ROW or META FUNCTIONS / SHOW INFO commands // we don't want to add the @timestamp field in this case https://github.com/elastic/kibana/issues/163417 - if (indexPattern && dataView?.fields?.getByName?.('@timestamp')?.type === 'date') { + if (!timeField && indexPattern && dataView?.fields?.getByName?.('@timestamp')?.type === 'date') { dataView.timeFieldName = '@timestamp'; } diff --git a/packages/kbn-esql-utils/src/utils/query_parsing_helpers.test.ts b/packages/kbn-esql-utils/src/utils/query_parsing_helpers.test.ts index ab5c1ca04ac7f..0366b1aba9f36 100644 --- a/packages/kbn-esql-utils/src/utils/query_parsing_helpers.test.ts +++ b/packages/kbn-esql-utils/src/utils/query_parsing_helpers.test.ts @@ -11,6 +11,7 @@ import { getLimitFromESQLQuery, removeDropCommandsFromESQLQuery, hasTransformationalCommand, + getTimeFieldFromESQLQuery, } from './query_parsing_helpers'; describe('esql query helpers', () => { @@ -142,4 +143,36 @@ describe('esql query helpers', () => { expect(hasTransformationalCommand('metrics a var = avg(b)')).toBeTruthy(); }); }); + + describe('getTimeFieldFromESQLQuery', () => { + it('should return undefined if there are no time params', () => { + expect(getTimeFieldFromESQLQuery('from a | eval b = 1')).toBeUndefined(); + }); + + it('should return the time field if there is at least one time param', () => { + expect(getTimeFieldFromESQLQuery('from a | eval b = 1 | where time >= ?earliest')).toBe( + 'time' + ); + }); + + it('should return undefined if there is one named param but is not ?earliest or ?latest', () => { + expect( + getTimeFieldFromESQLQuery('from a | eval b = 1 | where time >= ?late') + ).toBeUndefined(); + }); + + it('should return undefined if there is one named param but is used without a time field', () => { + expect( + getTimeFieldFromESQLQuery('from a | eval b = DATE_TRUNC(1 day, ?earliest)') + ).toBeUndefined(); + }); + + it('should return the time field if there is at least one time param in the bucket function', () => { + expect( + getTimeFieldFromESQLQuery( + 'from a | stats meow = avg(bytes) by bucket(event.timefield, 200, ?earliest, ?latest)' + ) + ).toBe('event.timefield'); + }); + }); }); diff --git a/packages/kbn-esql-utils/src/utils/query_parsing_helpers.ts b/packages/kbn-esql-utils/src/utils/query_parsing_helpers.ts index 79a3bbdd900d9..e683bd8b511c7 100644 --- a/packages/kbn-esql-utils/src/utils/query_parsing_helpers.ts +++ b/packages/kbn-esql-utils/src/utils/query_parsing_helpers.ts @@ -5,7 +5,8 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import { type ESQLSource, getAstAndSyntaxErrors } from '@kbn/esql-ast'; +import type { ESQLSource, ESQLFunction, ESQLColumn, ESQLSingleAstItem } from '@kbn/esql-ast'; +import { getAstAndSyntaxErrors, Walker, walk } from '@kbn/esql-ast'; const DEFAULT_ESQL_LIMIT = 500; @@ -53,3 +54,41 @@ export function removeDropCommandsFromESQLQuery(esql?: string): string { const pipes = (esql || '').split('|'); return pipes.filter((statement) => !/DROP\s/i.test(statement)).join('|'); } + +/** + * When the ?earliest and ?latest params are used, we want to retrieve the timefield from the query. + * @param esql:string + * @returns string + */ +export const getTimeFieldFromESQLQuery = (esql: string) => { + const { ast } = getAstAndSyntaxErrors(esql); + const functions: ESQLFunction[] = []; + + walk(ast, { + visitFunction: (node) => functions.push(node), + }); + + const params = Walker.params(ast); + const timeNamedParam = params.find( + (param) => param.value === 'earliest' || param.value === 'latest' + ); + if (!timeNamedParam || !functions.length) { + return undefined; + } + const allFunctionsWithNamedParams = functions.filter( + ({ location }) => + location.min <= timeNamedParam.location.min && location.max >= timeNamedParam.location.max + ); + + if (!allFunctionsWithNamedParams.length) { + return undefined; + } + const lowLevelFunction = allFunctionsWithNamedParams[allFunctionsWithNamedParams.length - 1]; + + const column = lowLevelFunction.args.find((arg) => { + const argument = arg as ESQLSingleAstItem; + return argument.type === 'column'; + }) as ESQLColumn; + + return column?.name; +}; diff --git a/packages/kbn-esql-utils/src/utils/run_query.test.ts b/packages/kbn-esql-utils/src/utils/run_query.test.ts new file mode 100644 index 0000000000000..ba8a22f98a7a7 --- /dev/null +++ b/packages/kbn-esql-utils/src/utils/run_query.test.ts @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import { getEarliestLatestParams } from './run_query'; + +describe('getEarliestLatestParams', () => { + it('should return an empty array if there are no time params', () => { + const time = { from: 'now-15m', to: 'now' }; + const query = 'FROM foo'; + const params = getEarliestLatestParams(query, time); + expect(params).toEqual([]); + }); + + it('should return an array with the earliest param if exists at the query', () => { + const time = { from: 'Jul 5, 2024 @ 08:03:56.849', to: 'Jul 5, 2024 @ 10:03:56.849' }; + const query = 'FROM foo | where time > ?earliest'; + const params = getEarliestLatestParams(query, time); + expect(params).toHaveLength(1); + expect(params[0]).toHaveProperty('earliest'); + }); + + it('should return an array with the latest param if exists at the query', () => { + const time = { from: 'Jul 5, 2024 @ 08:03:56.849', to: 'Jul 5, 2024 @ 10:03:56.849' }; + const query = 'FROM foo | where time < ?latest'; + const params = getEarliestLatestParams(query, time); + expect(params).toHaveLength(1); + expect(params[0]).toHaveProperty('latest'); + }); + + it('should return an array with the latest and earliest params if exist at the query', () => { + const time = { from: 'Jul 5, 2024 @ 08:03:56.849', to: 'Jul 5, 2024 @ 10:03:56.849' }; + const query = 'FROM foo | where time < ?latest amd time > ?earliest'; + const params = getEarliestLatestParams(query, time); + expect(params).toHaveLength(2); + expect(params[0]).toHaveProperty('earliest'); + expect(params[1]).toHaveProperty('latest'); + }); +}); diff --git a/packages/kbn-esql-utils/src/utils/run_query.ts b/packages/kbn-esql-utils/src/utils/run_query.ts index 7c52365d76b98..e562f7a882a3c 100644 --- a/packages/kbn-esql-utils/src/utils/run_query.ts +++ b/packages/kbn-esql-utils/src/utils/run_query.ts @@ -6,12 +6,36 @@ * Side Public License, v 1. */ import { i18n } from '@kbn/i18n'; +import dateMath from '@kbn/datemath'; import type { DatatableColumn } from '@kbn/expressions-plugin/common'; import type { ISearchGeneric } from '@kbn/search-types'; +import type { TimeRange } from '@kbn/es-query'; import { esFieldTypeToKibanaFieldType } from '@kbn/field-types'; import type { ESQLColumn, ESQLSearchResponse, ESQLSearchParams } from '@kbn/es-types'; import { lastValueFrom } from 'rxjs'; +export const hasEarliestLatestParams = (query: string) => /\?earliest|\?latest/i.test(query); + +export const getEarliestLatestParams = (query: string, time?: TimeRange) => { + const earliestNamedParams = /\?earliest/i.test(query); + const latestNamedParams = /\?latest/i.test(query); + if (time && (earliestNamedParams || latestNamedParams)) { + const timeParams = { + earliest: earliestNamedParams ? dateMath.parse(time.from)?.toISOString() : undefined, + latest: latestNamedParams ? dateMath.parse(time.to)?.toISOString() : undefined, + }; + const namedParams = []; + if (timeParams?.earliest) { + namedParams.push({ earliest: timeParams.earliest }); + } + if (timeParams?.latest) { + namedParams.push({ latest: timeParams.latest }); + } + return namedParams; + } + return []; +}; + export function formatESQLColumns(columns: ESQLColumn[]): DatatableColumn[] { return columns.map(({ name, type }) => { const kibanaType = esFieldTypeToKibanaFieldType(type); @@ -29,17 +53,21 @@ export async function getESQLQueryColumnsRaw({ esqlQuery, search, signal, + timeRange, }: { esqlQuery: string; search: ISearchGeneric; signal?: AbortSignal; + timeRange?: TimeRange; }): Promise { try { + const namedParams = getEarliestLatestParams(esqlQuery, timeRange); const response = await lastValueFrom( search( { params: { query: `${esqlQuery} | limit 0`, + ...(namedParams.length ? { params: namedParams } : {}), }, }, { @@ -66,13 +94,15 @@ export async function getESQLQueryColumns({ esqlQuery, search, signal, + timeRange, }: { esqlQuery: string; search: ISearchGeneric; signal?: AbortSignal; + timeRange?: TimeRange; }): Promise { try { - const rawColumns = await getESQLQueryColumnsRaw({ esqlQuery, search, signal }); + const rawColumns = await getESQLQueryColumnsRaw({ esqlQuery, search, signal, timeRange }); const columns = formatESQLColumns(rawColumns) ?? []; return columns; } catch (error) { @@ -93,16 +123,19 @@ export async function getESQLResults({ signal, filter, dropNullColumns, + timeRange, }: { esqlQuery: string; search: ISearchGeneric; signal?: AbortSignal; filter?: unknown; dropNullColumns?: boolean; + timeRange?: TimeRange; }): Promise<{ response: ESQLSearchResponse; params: ESQLSearchParams; }> { + const namedParams = getEarliestLatestParams(esqlQuery, timeRange); const result = await lastValueFrom( search( { @@ -110,6 +143,7 @@ export async function getESQLResults({ ...(filter ? { filter } : {}), query: esqlQuery, ...(dropNullColumns ? { dropNullColumns: true } : {}), + ...(namedParams.length ? { params: namedParams } : {}), }, }, { diff --git a/packages/kbn-esql-utils/tsconfig.json b/packages/kbn-esql-utils/tsconfig.json index a6470bec40ee1..79c447579d86c 100644 --- a/packages/kbn-esql-utils/tsconfig.json +++ b/packages/kbn-esql-utils/tsconfig.json @@ -24,6 +24,8 @@ "@kbn/expressions-plugin", "@kbn/field-types", "@kbn/es-types", - "@kbn/i18n" + "@kbn/i18n", + "@kbn/datemath", + "@kbn/es-query" ] } diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.from.test.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.from.test.ts new file mode 100644 index 0000000000000..3752fad6c580f --- /dev/null +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.from.test.ts @@ -0,0 +1,103 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { METADATA_FIELDS } from '../../shared/constants'; +import { setup, indexes, integrations } from './helpers'; + +const visibleIndices = indexes + .filter(({ hidden }) => !hidden) + .map(({ name, suggestedAs }) => suggestedAs || name) + .sort(); + +const metadataFields = [...METADATA_FIELDS].sort(); + +describe('autocomplete.suggest', () => { + describe('FROM [ METADATA ]', () => { + describe('FROM ...', () => { + test('suggests command on first character', async () => { + const { suggest } = await setup(); + + const suggestions = await suggest('f/'); + const hasCommand = !!suggestions.find((s) => s.label.toUpperCase() === 'FROM'); + + expect(hasCommand).toBe(true); + }); + }); + + describe('... ...', () => { + test('suggests visible indices on space', async () => { + const { assertSuggestions } = await setup(); + + await assertSuggestions('from /', visibleIndices); + await assertSuggestions('FROM /', visibleIndices); + await assertSuggestions('from /index', visibleIndices); + }); + + test('suggests visible indices on comma', async () => { + const { assertSuggestions } = await setup(); + + await assertSuggestions('FROM a,/', visibleIndices); + await assertSuggestions('FROM a, /', visibleIndices); + await assertSuggestions('from *,/', visibleIndices); + }); + + test('can suggest integration data sources', async () => { + const dataSources = indexes.concat(integrations); + const visibleDataSources = dataSources + .filter(({ hidden }) => !hidden) + .map(({ name, suggestedAs }) => suggestedAs || name) + .sort(); + const { assertSuggestions, callbacks } = await setup(); + const cb = { + ...callbacks, + getSources: jest.fn().mockResolvedValue(dataSources), + }; + + assertSuggestions('from /', visibleDataSources, { callbacks: cb }); + assertSuggestions('FROM /', visibleDataSources, { callbacks: cb }); + assertSuggestions('FROM a,/', visibleDataSources, { callbacks: cb }); + assertSuggestions('from a, /', visibleDataSources, { callbacks: cb }); + assertSuggestions('from *,/', visibleDataSources, { callbacks: cb }); + }); + }); + + describe('... METADATA ', () => { + const metadataFieldsSandIndex = metadataFields.filter((field) => field !== '_index'); + + test('on SPACE without comma ",", suggests adding metadata', async () => { + const { assertSuggestions } = await setup(); + const expected = ['METADATA $0', ',', '|'].sort(); + + await assertSuggestions('from a, b /', expected); + }); + + test('on SPACE after "METADATA" keyword suggests all metadata fields', async () => { + const { assertSuggestions } = await setup(); + + await assertSuggestions('from a, b [METADATA /]', metadataFields); + await assertSuggestions('from a, b METADATA /', metadataFields); + }); + + test('on SPACE after "METADATA" column suggests command and pipe operators', async () => { + const { assertSuggestions } = await setup(); + + await assertSuggestions('from a, b [metadata _index /]', [',', '|']); + await assertSuggestions('from a, b metadata _index /', [',', '|']); + await assertSuggestions('from a, b metadata _index, _source /', [',', '|']); + await assertSuggestions(`from a, b metadata ${METADATA_FIELDS.join(', ')} /`, ['|']); + }); + + test('filters out already used metadata fields', async () => { + const { assertSuggestions } = await setup(); + + await assertSuggestions('from a, b [metadata _index, /]', metadataFieldsSandIndex); + await assertSuggestions('from a, b metadata _index, /', metadataFieldsSandIndex); + }); + }); + }); +}); diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.stats.test.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.stats.test.ts new file mode 100644 index 0000000000000..2d81fe794193b --- /dev/null +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.stats.test.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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { setup, getFunctionSignaturesByReturnType, getFieldNamesByType } from './helpers'; + +const allAggFunctions = getFunctionSignaturesByReturnType('stats', 'any', { + agg: true, +}); + +const allEvaFunctions = getFunctionSignaturesByReturnType( + 'stats', + 'any', + { + evalMath: true, + grouping: false, + }, + undefined, + undefined, + 'by' +); + +const allGroupingFunctions = getFunctionSignaturesByReturnType( + 'stats', + 'any', + { + grouping: true, + }, + undefined, + undefined, + 'by' +); + +describe('autocomplete.suggest', () => { + describe('STATS [ BY ]', () => { + describe('STATS ...', () => {}); + + describe('... ...', () => { + test('lists possible aggregations on space after command', async () => { + const { assertSuggestions } = await setup(); + const expected = ['var0 =', ...allAggFunctions, ...allEvaFunctions]; + + await assertSuggestions('from a | stats /', expected); + await assertSuggestions('FROM a | STATS /', expected); + }); + + test('on assignment expression, shows all agg and eval functions', async () => { + const { assertSuggestions } = await setup(); + + await assertSuggestions('from a | stats a=/', [...allAggFunctions, ...allEvaFunctions]); + }); + + test('on space after aggregate field', async () => { + const { assertSuggestions } = await setup(); + + await assertSuggestions('from a | stats a=min(b) /', ['BY $0', ',', '|']); + }); + + test('on space after aggregate field with comma', async () => { + const { assertSuggestions } = await setup(); + + await assertSuggestions('from a | stats a=max(b), /', [ + 'var0 =', + ...allAggFunctions, + ...allEvaFunctions, + ]); + }); + + test('on function left paren', async () => { + const { assertSuggestions } = await setup(); + + await assertSuggestions( + 'from a | stats by bucket(/', + [ + ...getFieldNamesByType(['number', 'date']), + ...getFunctionSignaturesByReturnType('eval', ['date', 'number'], { evalMath: true }), + ].map((field) => `${field},`) + ); + + await assertSuggestions('from a | stats round(/', [ + ...getFunctionSignaturesByReturnType('stats', 'number', { agg: true, grouping: true }), + ...getFieldNamesByType('number'), + ...getFunctionSignaturesByReturnType('eval', 'number', { evalMath: true }, undefined, [ + 'round', + ]), + ]); + await assertSuggestions('from a | stats round(round(/', [ + ...getFunctionSignaturesByReturnType('stats', 'number', { agg: true }), + ...getFieldNamesByType('number'), + ...getFunctionSignaturesByReturnType('eval', 'number', { evalMath: true }, undefined, [ + 'round', + ]), + ]); + await assertSuggestions('from a | stats avg(round(/', [ + ...getFieldNamesByType('number'), + ...getFunctionSignaturesByReturnType('eval', 'number', { evalMath: true }, undefined, [ + 'round', + ]), + ]); + await assertSuggestions('from a | stats avg(/', [ + ...getFieldNamesByType('number'), + ...getFunctionSignaturesByReturnType('eval', 'number', { evalMath: true }), + ]); + await assertSuggestions('from a | stats round(avg(/', [ + ...getFieldNamesByType('number'), + ...getFunctionSignaturesByReturnType('eval', 'number', { evalMath: true }, undefined, [ + 'round', + ]), + ]); + }); + + test('when typing inside function left paren', async () => { + const { assertSuggestions } = await setup(); + const expected = [ + ...getFieldNamesByType(['number', 'date', 'boolean']), + ...getFunctionSignaturesByReturnType('stats', ['number', 'date', 'boolean'], { + evalMath: true, + }), + ]; + + await assertSuggestions('from a | stats a=min(/)', expected); + await assertSuggestions('from a | stats a=min(/b), b=max()', expected); + await assertSuggestions('from a | stats a=min(b), b=max(/)', expected); + }); + + test('inside function argument list', async () => { + const { assertSuggestions } = await setup(); + + await assertSuggestions('from a | stats avg(b/) by stringField', [ + ...getFieldNamesByType('number'), + ...getFunctionSignaturesByReturnType('eval', 'number', { evalMath: true }), + ]); + }); + + test('when typing right paren', async () => { + const { assertSuggestions } = await setup(); + + await assertSuggestions('from a | stats a = min(b)/ | sort b', ['BY $0', ',', '|']); + }); + + test('increments suggested variable name counter', async () => { + const { assertSuggestions } = await setup(); + + await assertSuggestions('from a | eval var0=round(b), var1=round(c) | stats /', [ + 'var2 =', + ...allAggFunctions, + 'var0', + 'var1', + ...allEvaFunctions, + ]); + await assertSuggestions('from a | stats var0=min(b),var1=c,/', [ + 'var2 =', + ...allAggFunctions, + ...allEvaFunctions, + ]); + }); + }); + + describe('... BY ', () => { + test('on space after "BY" keyword', async () => { + const { assertSuggestions } = await setup(); + const expected = [ + 'var0 =', + ...getFieldNamesByType('any'), + ...allEvaFunctions, + ...allGroupingFunctions, + ]; + + await assertSuggestions('from a | stats a=max(b) by /', expected); + await assertSuggestions('from a | stats a=max(b) BY /', expected); + await assertSuggestions('from a | stats a=min(b) by /', expected); + }); + + test('on space after grouping field', async () => { + const { assertSuggestions } = await setup(); + + await assertSuggestions('from a | stats a=c by d /', [',', '|']); + }); + + test('after comma "," in grouping fields', async () => { + const { assertSuggestions } = await setup(); + + await assertSuggestions('from a | stats a=c by d, /', [ + 'var0 =', + ...getFieldNamesByType('any'), + ...allEvaFunctions, + ...allGroupingFunctions, + ]); + await assertSuggestions('from a | stats a=min(b),/', [ + 'var0 =', + ...allAggFunctions, + ...allEvaFunctions, + ]); + await assertSuggestions('from a | stats avg(b) by c, /', [ + 'var0 =', + ...getFieldNamesByType('any'), + ...getFunctionSignaturesByReturnType('eval', 'any', { evalMath: true }), + ...allGroupingFunctions, + ]); + }); + + test('on space before expression right hand side operand', async () => { + const { assertSuggestions } = await setup(); + + await assertSuggestions('from a | stats avg(b) by numberField % /', [ + ...getFieldNamesByType('number'), + '`avg(b)`', + ...getFunctionSignaturesByReturnType('eval', 'number', { evalMath: true }), + ...allGroupingFunctions, + ]); + await assertSuggestions('from a | stats avg(b) by var0 = /', [ + ...getFieldNamesByType('any'), + ...allEvaFunctions, + ...allGroupingFunctions, + ]); + await assertSuggestions('from a | stats avg(b) by c, var0 = /', [ + ...getFieldNamesByType('any'), + ...allEvaFunctions, + ...allGroupingFunctions, + ]); + }); + + test('on space after expression right hand side operand', async () => { + const { assertSuggestions } = await setup(); + + await assertSuggestions('from a | stats avg(b) by numberField % 2 /', [',', '|']); + }); + }); + }); +}); diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/helpers.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/helpers.ts new file mode 100644 index 0000000000000..657b5de67896e --- /dev/null +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/helpers.ts @@ -0,0 +1,311 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { camelCase } from 'lodash'; +import { getAstAndSyntaxErrors } from '@kbn/esql-ast'; +import { evalFunctionDefinitions } from '../../definitions/functions'; +import { builtinFunctions } from '../../definitions/builtin'; +import { statsAggregationFunctionDefinitions } from '../../definitions/aggs'; +import { timeUnitsToSuggest } from '../../definitions/literals'; +import { groupingFunctionDefinitions } from '../../definitions/grouping'; +import * as autocomplete from '../autocomplete'; +import type { ESQLCallbacks } from '../../shared/types'; +import type { EditorContext } from '../types'; +import { TIME_SYSTEM_PARAMS } from '../factories'; + +export interface Integration { + name: string; + hidden: boolean; + title?: string; + dataStreams: Array<{ + name: string; + title?: string; + }>; +} + +export const triggerCharacters = [',', '(', '=', ' ']; + +export const fields: Array<{ name: string; type: string; suggestedAs?: string }> = [ + ...[ + 'string', + 'number', + 'date', + 'boolean', + 'ip', + 'geo_point', + 'geo_shape', + 'cartesian_point', + 'cartesian_shape', + ].map((type) => ({ + name: `${camelCase(type)}Field`, + type, + })), + { name: 'any#Char$Field', type: 'number', suggestedAs: '`any#Char$Field`' }, + { name: 'kubernetes.something.something', type: 'number' }, +]; + +export const indexes = ( + [] as Array<{ name: string; hidden: boolean; suggestedAs?: string }> +).concat( + [ + 'a', + 'index', + 'otherIndex', + '.secretIndex', + 'my-index', + 'my-index$', + 'my_index{}', + 'my-index+1', + 'synthetics-*', + ].map((name) => ({ + name, + hidden: name.startsWith('.'), + })), + ['my-index[quoted]', 'my:index', 'my,index', 'logstash-{now/d{yyyy.MM.dd|+12:00}}'].map( + (name) => ({ + name, + hidden: false, + suggestedAs: `"${name}"`, + }) + ) +); + +export const integrations: Integration[] = ['nginx', 'k8s'].map((name) => ({ + name, + hidden: false, + title: `integration-${name}`, + dataStreams: [ + { + name: `${name}-1`, + title: `integration-${name}-1`, + }, + ], +})); + +export const policies = [ + { + name: 'policy', + sourceIndices: ['enrichIndex1'], + matchField: 'otherStringField', + enrichFields: ['otherField', 'yetAnotherField', 'yet-special-field'], + suggestedAs: undefined, + }, + ...['my-policy[quoted]', 'my-policy$', 'my_policy{}'].map((name) => ({ + name, + sourceIndices: ['enrichIndex1'], + matchField: 'otherStringField', + enrichFields: ['otherField', 'yetAnotherField', 'yet-special-field'], + suggestedAs: `\`${name}\``, + })), +]; + +/** + * Utility to filter down the function list for the given type + * It is mainly driven by the return type, but it can be filtered upon with the last optional argument "paramsTypes" + * jsut make sure to pass the arguments in the right order + * @param command current command context + * @param expectedReturnType the expected type returned by the function + * @param functionCategories + * @param paramsTypes the function argument types (optional) + * @returns + */ +export function getFunctionSignaturesByReturnType( + command: string, + _expectedReturnType: string | string[], + { + agg, + grouping, + evalMath, + builtin, + // skipAssign here is used to communicate to not propose an assignment if it's not possible + // within the current context (the actual logic has it, but here we want a shortcut) + skipAssign, + }: { + agg?: boolean; + grouping?: boolean; + evalMath?: boolean; + builtin?: boolean; + skipAssign?: boolean; + } = {}, + paramsTypes?: string[], + ignored?: string[], + option?: string +) { + const expectedReturnType = Array.isArray(_expectedReturnType) + ? _expectedReturnType + : [_expectedReturnType]; + + const list = []; + if (agg) { + list.push(...statsAggregationFunctionDefinitions); + // right now all grouping functions are agg functions too + list.push(...groupingFunctionDefinitions); + } + if (grouping) { + list.push(...groupingFunctionDefinitions); + } + // eval functions (eval is a special keyword in JS) + if (evalMath) { + list.push(...evalFunctionDefinitions); + } + if (builtin) { + list.push(...builtinFunctions.filter(({ name }) => (skipAssign ? name !== '=' : true))); + } + + const deduped = Array.from(new Set(list)); + + return deduped + .filter(({ signatures, ignoreAsSuggestion, supportedCommands, supportedOptions, name }) => { + if (ignoreAsSuggestion) { + return false; + } + if (!supportedCommands.includes(command) && !supportedOptions?.includes(option || '')) { + return false; + } + const filteredByReturnType = signatures.filter( + ({ returnType }) => + expectedReturnType.includes('any') || expectedReturnType.includes(returnType) + ); + if (!filteredByReturnType.length) { + return false; + } + if (paramsTypes?.length) { + return filteredByReturnType.some( + ({ params }) => + !params.length || + (paramsTypes.length <= params.length && + paramsTypes.every( + (expectedType, i) => + expectedType === 'any' || + params[i].type === 'any' || + expectedType === params[i].type + )) + ); + } + return true; + }) + .filter(({ name }) => { + if (ignored?.length) { + return !ignored?.includes(name); + } + return true; + }) + .sort(({ name: a }, { name: b }) => a.localeCompare(b)) + .map(({ type, name, signatures }) => { + if (type === 'builtin') { + return signatures.some(({ params }) => params.length > 1) + ? `${name.toUpperCase()} $0` + : name.toUpperCase(); + } + return `${name.toUpperCase()}($0)`; + }); +} + +export function getFieldNamesByType(_requestedType: string | string[]) { + const requestedType = Array.isArray(_requestedType) ? _requestedType : [_requestedType]; + return fields + .filter(({ type }) => requestedType.includes('any') || requestedType.includes(type)) + .map(({ name, suggestedAs }) => suggestedAs || name); +} + +export function getLiteralsByType(_type: string | string[]) { + const type = Array.isArray(_type) ? _type : [_type]; + if (type.includes('time_literal')) { + // return only singular + return timeUnitsToSuggest.map(({ name }) => `1 ${name}`).filter((s) => !/s$/.test(s)); + } + return []; +} + +export function getDateLiteralsByFieldType(_requestedType: string | string[]) { + const requestedType = Array.isArray(_requestedType) ? _requestedType : [_requestedType]; + return requestedType.includes('date') ? TIME_SYSTEM_PARAMS : []; +} + +export function createCustomCallbackMocks( + customFields?: Array<{ name: string; type: string }>, + customSources?: Array<{ name: string; hidden: boolean }>, + customPolicies?: Array<{ + name: string; + sourceIndices: string[]; + matchField: string; + enrichFields: string[]; + }> +) { + const finalFields = customFields || fields; + const finalSources = customSources || indexes; + const finalPolicies = customPolicies || policies; + return { + getFieldsFor: jest.fn(async () => finalFields), + getSources: jest.fn(async () => finalSources), + getPolicies: jest.fn(async () => finalPolicies), + }; +} + +export function createSuggestContext(text: string, triggerCharacter?: string) { + if (triggerCharacter) { + return { triggerCharacter, triggerKind: 1 }; // any number is fine here + } + const foundTriggerCharIndexes = triggerCharacters.map((char) => text.lastIndexOf(char)); + const maxIndex = Math.max(...foundTriggerCharIndexes); + return { + triggerCharacter: text[maxIndex], + triggerKind: 1, + }; +} + +export function getPolicyFields(policyName: string) { + return policies + .filter(({ name }) => name === policyName) + .flatMap(({ enrichFields }) => + // ok, this is a bit of cheating as it's using the same logic as in the helper + enrichFields.map((field) => (/[^a-zA-Z\d_\.@]/.test(field) ? `\`${field}\`` : field)) + ); +} + +export interface SuggestOptions { + ctx?: EditorContext; + callbacks?: ESQLCallbacks; +} + +export const setup = async (caret = '/') => { + if (caret.length !== 1) { + throw new Error('Caret must be a single character'); + } + + const callbacks = createCustomCallbackMocks(); + + const suggest = async (query: string, opts: SuggestOptions = {}) => { + const pos = query.indexOf(caret); + if (pos < 0) throw new Error(`User cursor/caret "${caret}" not found in query: ${query}`); + const querySansCaret = query.slice(0, pos) + query.slice(pos + 1); + const ctx = + opts.ctx ?? + (pos > 0 ? { triggerKind: 1, triggerCharacter: query[pos - 1] } : { triggerKind: 0 }); + return await autocomplete.suggest( + querySansCaret, + pos, + ctx, + getAstAndSyntaxErrors, + opts.callbacks ?? callbacks + ); + }; + + const assertSuggestions = async (query: string, expected: string[], opts?: SuggestOptions) => { + const result = await suggest(query, opts); + const resultTexts = [...result.map((suggestion) => suggestion.text)].sort(); + + expect(resultTexts).toEqual([...expected].sort()); + }; + + return { + callbacks, + suggest, + assertSuggestions, + }; +}; 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 495452bed4b08..687684f6fcf34 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts @@ -8,262 +8,24 @@ import { suggest } from './autocomplete'; import { evalFunctionDefinitions } from '../definitions/functions'; -import { builtinFunctions } from '../definitions/builtin'; -import { statsAggregationFunctionDefinitions } from '../definitions/aggs'; import { timeUnitsToSuggest } from '../definitions/literals'; import { commandDefinitions } from '../definitions/commands'; -import { getUnitDuration, TRIGGER_SUGGESTION_COMMAND } from './factories'; +import { getUnitDuration, TRIGGER_SUGGESTION_COMMAND, TIME_SYSTEM_PARAMS } from './factories'; import { camelCase, partition } from 'lodash'; import { getAstAndSyntaxErrors } from '@kbn/esql-ast'; -import { groupingFunctionDefinitions } from '../definitions/grouping'; import { FunctionParameter } from '../definitions/types'; import { getParamAtPosition } from './helper'; import { nonNullable } from '../shared/helpers'; -import { METADATA_FIELDS } from '../shared/constants'; - -interface Integration { - name: string; - hidden: boolean; - title?: string; - dataStreams: Array<{ - name: string; - title?: string; - }>; -} - -const triggerCharacters = [',', '(', '=', ' ']; - -const fields: Array<{ name: string; type: string; suggestedAs?: string }> = [ - ...[ - 'string', - 'number', - 'date', - 'boolean', - 'ip', - 'geo_point', - 'geo_shape', - 'cartesian_point', - 'cartesian_shape', - ].map((type) => ({ - name: `${camelCase(type)}Field`, - type, - })), - { name: 'any#Char$Field', type: 'number', suggestedAs: '`any#Char$Field`' }, - { name: 'kubernetes.something.something', type: 'number' }, -]; - -const indexes = ([] as Array<{ name: string; hidden: boolean; suggestedAs?: string }>).concat( - [ - 'a', - 'index', - 'otherIndex', - '.secretIndex', - 'my-index', - 'my-index$', - 'my_index{}', - 'my-index+1', - 'synthetics-*', - ].map((name) => ({ - name, - hidden: name.startsWith('.'), - })), - ['my-index[quoted]', 'my:index', 'my,index', 'logstash-{now/d{yyyy.MM.dd|+12:00}}'].map( - (name) => ({ - name, - hidden: false, - suggestedAs: `"${name}"`, - }) - ) -); - -const integrations: Integration[] = ['nginx', 'k8s'].map((name) => ({ - name, - hidden: false, - title: `integration-${name}`, - dataStreams: [ - { - name: `${name}-1`, - title: `integration-${name}-1`, - }, - ], -})); -const policies = [ - { - name: 'policy', - sourceIndices: ['enrichIndex1'], - matchField: 'otherStringField', - enrichFields: ['otherField', 'yetAnotherField', 'yet-special-field'], - suggestedAs: undefined, - }, - ...['my-policy[quoted]', 'my-policy$', 'my_policy{}'].map((name) => ({ - name, - sourceIndices: ['enrichIndex1'], - matchField: 'otherStringField', - enrichFields: ['otherField', 'yetAnotherField', 'yet-special-field'], - suggestedAs: `\`${name}\``, - })), -]; - -/** - * Utility to filter down the function list for the given type - * It is mainly driven by the return type, but it can be filtered upon with the last optional argument "paramsTypes" - * jsut make sure to pass the arguments in the right order - * @param command current command context - * @param expectedReturnType the expected type returned by the function - * @param functionCategories - * @param paramsTypes the function argument types (optional) - * @returns - */ -function getFunctionSignaturesByReturnType( - command: string, - _expectedReturnType: string | string[], - { - agg, - grouping, - evalMath, - builtin, - // skipAssign here is used to communicate to not propose an assignment if it's not possible - // within the current context (the actual logic has it, but here we want a shortcut) - skipAssign, - }: { - agg?: boolean; - grouping?: boolean; - evalMath?: boolean; - builtin?: boolean; - skipAssign?: boolean; - } = {}, - paramsTypes?: string[], - ignored?: string[], - option?: string -) { - const expectedReturnType = Array.isArray(_expectedReturnType) - ? _expectedReturnType - : [_expectedReturnType]; - - const list = []; - if (agg) { - list.push(...statsAggregationFunctionDefinitions); - // right now all grouping functions are agg functions too - list.push(...groupingFunctionDefinitions); - } - if (grouping) { - list.push(...groupingFunctionDefinitions); - } - // eval functions (eval is a special keyword in JS) - if (evalMath) { - list.push(...evalFunctionDefinitions); - } - if (builtin) { - list.push(...builtinFunctions.filter(({ name }) => (skipAssign ? name !== '=' : true))); - } - - const deduped = Array.from(new Set(list)); - - return deduped - .filter(({ signatures, ignoreAsSuggestion, supportedCommands, supportedOptions, name }) => { - if (ignoreAsSuggestion) { - return false; - } - if (!supportedCommands.includes(command) && !supportedOptions?.includes(option || '')) { - return false; - } - const filteredByReturnType = signatures.filter( - ({ returnType }) => - expectedReturnType.includes('any') || expectedReturnType.includes(returnType) - ); - if (!filteredByReturnType.length) { - return false; - } - if (paramsTypes?.length) { - return filteredByReturnType.some( - ({ params }) => - !params.length || - (paramsTypes.length <= params.length && - paramsTypes.every( - (expectedType, i) => - expectedType === 'any' || - params[i].type === 'any' || - expectedType === params[i].type - )) - ); - } - return true; - }) - .filter(({ name }) => { - if (ignored?.length) { - return !ignored?.includes(name); - } - return true; - }) - .sort(({ name: a }, { name: b }) => a.localeCompare(b)) - .map(({ type, name, signatures }) => { - if (type === 'builtin') { - return signatures.some(({ params }) => params.length > 1) - ? `${name.toUpperCase()} $0` - : name.toUpperCase(); - } - return `${name.toUpperCase()}($0)`; - }); -} - -function getFieldNamesByType(_requestedType: string | string[]) { - const requestedType = Array.isArray(_requestedType) ? _requestedType : [_requestedType]; - return fields - .filter(({ type }) => requestedType.includes('any') || requestedType.includes(type)) - .map(({ name, suggestedAs }) => suggestedAs || name); -} - -function getLiteralsByType(_type: string | string[]) { - const type = Array.isArray(_type) ? _type : [_type]; - if (type.includes('time_literal')) { - // return only singular - return timeUnitsToSuggest.map(({ name }) => `1 ${name}`).filter((s) => !/s$/.test(s)); - } - return []; -} - -function createCustomCallbackMocks( - customFields: Array<{ name: string; type: string }> | undefined, - customSources: Array<{ name: string; hidden: boolean }> | undefined, - customPolicies: - | Array<{ - name: string; - sourceIndices: string[]; - matchField: string; - enrichFields: string[]; - }> - | undefined -) { - const finalFields = customFields || fields; - const finalSources = customSources || indexes; - const finalPolicies = customPolicies || policies; - return { - getFieldsFor: jest.fn(async () => finalFields), - getSources: jest.fn(async () => finalSources), - getPolicies: jest.fn(async () => finalPolicies), - }; -} - -function createSuggestContext(text: string, triggerCharacter?: string) { - if (triggerCharacter) { - return { triggerCharacter, triggerKind: 1 }; // any number is fine here - } - const foundTriggerCharIndexes = triggerCharacters.map((char) => text.lastIndexOf(char)); - const maxIndex = Math.max(...foundTriggerCharIndexes); - return { - triggerCharacter: text[maxIndex], - triggerKind: 1, - }; -} - -function getPolicyFields(policyName: string) { - return policies - .filter(({ name }) => name === policyName) - .flatMap(({ enrichFields }) => - // ok, this is a bit of cheating as it's using the same logic as in the helper - enrichFields.map((field) => (/[^a-zA-Z\d_\.@]/.test(field) ? `\`${field}\`` : field)) - ); -} +import { + policies, + getFunctionSignaturesByReturnType, + getFieldNamesByType, + getLiteralsByType, + getDateLiteralsByFieldType, + createCustomCallbackMocks, + createSuggestContext, + getPolicyFields, +} from './__tests__/helpers'; describe('autocomplete', () => { type TestArgs = [ @@ -295,26 +57,21 @@ describe('autocomplete', () => { : triggerCharacter; const testFn = only ? test.only : skip ? test.skip : test; - testFn( - `${statement} (triggerChar: "${context.triggerCharacter}" @ ${offset})=> ["${expected.join( - '","' - )}"]`, - async () => { - const callbackMocks = createCustomCallbackMocks(...customCallbacksArgs); - const suggestions = await suggest( - statement, - offset, - context, - async (text) => (text ? getAstAndSyntaxErrors(text) : { ast: [], errors: [] }), - callbackMocks - ); + testFn(statement, async () => { + const callbackMocks = createCustomCallbackMocks(...customCallbacksArgs); + const suggestions = await suggest( + statement, + offset, + context, + async (text) => (text ? getAstAndSyntaxErrors(text) : { ast: [], errors: [] }), + callbackMocks + ); - const sortedSuggestions = suggestions.map((suggestion) => suggestion.text).sort(); - const sortedExpected = expected.sort(); + const sortedSuggestions = suggestions.map((suggestion) => suggestion.text).sort(); + const sortedExpected = expected.sort(); - expect(sortedSuggestions).toEqual(sortedExpected); - } - ); + expect(sortedSuggestions).toEqual(sortedExpected); + }); }; // Enrich the function to work with .only and .skip as regular test function @@ -376,43 +133,6 @@ describe('autocomplete', () => { ); }); - describe('from', () => { - const suggestedIndexes = indexes - .filter(({ hidden }) => !hidden) - .map(({ name, suggestedAs }) => suggestedAs || name); - // Monaco will filter further down here - testSuggestions( - 'f', - sourceCommands.map((name) => name.toUpperCase() + ' $0') - ); - testSuggestions('from ', suggestedIndexes); - testSuggestions('from a,', suggestedIndexes); - testSuggestions('from a, b ', ['METADATA $0', ',', '|']); - testSuggestions('from *,', suggestedIndexes); - testSuggestions('from index', suggestedIndexes, 5 /* space before index */); - testSuggestions('from a, b [metadata ]', METADATA_FIELDS, ' ]'); - testSuggestions('from a, b metadata ', METADATA_FIELDS, ' '); - testSuggestions( - 'from a, b [metadata _index, ]', - METADATA_FIELDS.filter((field) => field !== '_index'), - ' ]' - ); - testSuggestions( - 'from a, b metadata _index, ', - METADATA_FIELDS.filter((field) => field !== '_index'), - ' ' - ); - - // with integrations support - const dataSources = indexes.concat(integrations); - const suggestedDataSources = dataSources - .filter(({ hidden }) => !hidden) - .map(({ name, suggestedAs }) => suggestedAs || name); - testSuggestions('from ', suggestedDataSources, '', [undefined, dataSources, undefined]); - testSuggestions('from a,', suggestedDataSources, '', [undefined, dataSources, undefined]); - testSuggestions('from *,', suggestedDataSources, '', [undefined, dataSources, undefined]); - }); - describe('show', () => { testSuggestions('show ', ['INFO']); for (const fn of ['info']) { @@ -653,198 +373,6 @@ describe('autocomplete', () => { }); } - describe('stats', () => { - const allAggFunctions = getFunctionSignaturesByReturnType('stats', 'any', { - agg: true, - }); - const allEvaFunctions = getFunctionSignaturesByReturnType( - 'stats', - 'any', - { - evalMath: true, - grouping: false, - }, - undefined, - undefined, - 'by' - ); - const allGroupingFunctions = getFunctionSignaturesByReturnType( - 'stats', - 'any', - { - grouping: true, - }, - undefined, - undefined, - 'by' - ); - testSuggestions('from a | stats ', ['var0 =', ...allAggFunctions, ...allEvaFunctions]); - testSuggestions('from a | stats a ', ['= $0']); - testSuggestions('from a | stats a=', [...allAggFunctions, ...allEvaFunctions]); - testSuggestions('from a | stats a=max(b) by ', [ - 'var0 =', - ...getFieldNamesByType('any'), - ...allEvaFunctions, - ...allGroupingFunctions, - ]); - testSuggestions('from a | stats a=max(b) BY ', [ - 'var0 =', - ...getFieldNamesByType('any'), - ...allEvaFunctions, - ...allGroupingFunctions, - ]); - testSuggestions('from a | stats a=c by d ', [',', '|']); - testSuggestions('from a | stats a=c by d, ', [ - 'var0 =', - ...getFieldNamesByType('any'), - ...allEvaFunctions, - ...allGroupingFunctions, - ]); - testSuggestions('from a | stats a=max(b), ', [ - 'var0 =', - ...allAggFunctions, - ...allEvaFunctions, - ]); - testSuggestions( - 'from a | stats a=min()', - [ - ...getFieldNamesByType(['number', 'date', 'boolean']), - ...getFunctionSignaturesByReturnType('stats', ['number', 'date', 'boolean'], { - evalMath: true, - }), - ], - '(' - ); - testSuggestions('from a | stats a=min(b) ', ['BY $0', ',', '|']); - testSuggestions('from a | stats a=min(b) by ', [ - 'var0 =', - ...getFieldNamesByType('any'), - ...allEvaFunctions, - ...allGroupingFunctions, - ]); - testSuggestions('from a | stats a=min(b),', ['var0 =', ...allAggFunctions, ...allEvaFunctions]); - testSuggestions('from a | stats var0=min(b),var1=c,', [ - 'var2 =', - ...allAggFunctions, - ...allEvaFunctions, - ]); - testSuggestions( - 'from a | stats a=min(b), b=max()', - [ - ...getFieldNamesByType(['number', 'date', 'boolean']), - ...getFunctionSignaturesByReturnType('stats', ['number', 'date', 'boolean'], { - evalMath: true, - }), - ], - '(' - ); - - testSuggestions('from a | eval var0=round(b), var1=round(c) | stats ', [ - 'var2 =', - ...allAggFunctions, - 'var0', - 'var1', - ...allEvaFunctions, - ]); - - // smoke testing with suggestions not at the end of the string - testSuggestions('from a | stats a = min(b) | sort b', ['BY $0', ',', '|'], ') '); - testSuggestions( - 'from a | stats avg(b) by stringField', - [ - ...getFieldNamesByType('number'), - ...getFunctionSignaturesByReturnType('eval', 'number', { evalMath: true }), - ], - '(b' - ); - - // while nested functions are not suggested, complete them should be possible via suggestions - testSuggestions('from a | stats avg(b) by numberField % ', [ - ...getFieldNamesByType('number'), - '`avg(b)`', - ...getFunctionSignaturesByReturnType('eval', 'number', { evalMath: true }), - ...allGroupingFunctions, - ]); - testSuggestions('from a | stats avg(b) by var0 = ', [ - ...getFieldNamesByType('any'), - ...allEvaFunctions, - ...allGroupingFunctions, - ]); - testSuggestions('from a | stats avg(b) by c, ', [ - 'var0 =', - ...getFieldNamesByType('any'), - ...getFunctionSignaturesByReturnType('eval', 'any', { evalMath: true }), - ...allGroupingFunctions, - ]); - testSuggestions('from a | stats avg(b) by c, var0 = ', [ - ...getFieldNamesByType('any'), - ...allEvaFunctions, - ...allGroupingFunctions, - ]); - - // expect "bucket" NOT to be suggested for its own parameter - testSuggestions( - 'from a | stats by bucket(', - [ - ...getFieldNamesByType(['number', 'date']), - ...getFunctionSignaturesByReturnType('eval', ['date', 'number'], { evalMath: true }), - ].map((field) => `${field},`) - ); - - testSuggestions('from a | stats avg(b) by numberField % 2 ', [',', '|']); - - testSuggestions( - 'from a | stats round(', - [ - ...getFunctionSignaturesByReturnType('stats', 'number', { agg: true, grouping: true }), - ...getFieldNamesByType('number'), - ...getFunctionSignaturesByReturnType('eval', 'number', { evalMath: true }, undefined, [ - 'round', - ]), - ], - '(' - ); - testSuggestions( - 'from a | stats round(round(', - [ - ...getFunctionSignaturesByReturnType('stats', 'number', { agg: true }), - ...getFieldNamesByType('number'), - ...getFunctionSignaturesByReturnType('eval', 'number', { evalMath: true }, undefined, [ - 'round', - ]), - ], - '(' - ); - testSuggestions( - 'from a | stats avg(round(', - [ - ...getFieldNamesByType('number'), - ...getFunctionSignaturesByReturnType('eval', 'number', { evalMath: true }, undefined, [ - 'round', - ]), - ], - '(' - ); - testSuggestions( - 'from a | stats avg(', - [ - ...getFieldNamesByType('number'), - ...getFunctionSignaturesByReturnType('eval', 'number', { evalMath: true }), - ], - '(' - ); - testSuggestions( - 'from a | stats round(avg(', - [ - ...getFieldNamesByType('number'), - ...getFunctionSignaturesByReturnType('eval', 'number', { evalMath: true }, undefined, [ - 'round', - ]), - ], - '(' - ); - }); - describe('enrich', () => { const modes = ['any', 'coordinator', 'remote']; const policyNames = policies.map(({ name, suggestedAs }) => suggestedAs || name); @@ -1203,6 +731,9 @@ describe('autocomplete', () => { suggestedConstants?.length ? suggestedConstants.map((option) => `"${option}"${requiresMoreArgs ? ',' : ''}`) : [ + ...getDateLiteralsByFieldType( + getTypesFromParamDefs(acceptsFieldParamDefs) + ).map((l) => (requiresMoreArgs ? `${l},` : l)), ...getFieldNamesByType(getTypesFromParamDefs(acceptsFieldParamDefs)).map( (f) => (requiresMoreArgs ? `${f},` : f) ), @@ -1225,6 +756,9 @@ describe('autocomplete', () => { suggestedConstants?.length ? suggestedConstants.map((option) => `"${option}"${requiresMoreArgs ? ',' : ''}`) : [ + ...getDateLiteralsByFieldType( + getTypesFromParamDefs(acceptsFieldParamDefs) + ).map((l) => (requiresMoreArgs ? `${l},` : l)), ...getFieldNamesByType(getTypesFromParamDefs(acceptsFieldParamDefs)).map( (f) => (requiresMoreArgs ? `${f},` : f) ), @@ -1283,6 +817,7 @@ describe('autocomplete', () => { testSuggestions( 'from a | eval var0=date_trunc()', [ + ...TIME_SYSTEM_PARAMS.map((t) => `${t},`), ...getLiteralsByType('time_literal').map((t) => `${t},`), ...getFunctionSignaturesByReturnType('eval', 'date', { evalMath: true }, undefined, [ 'date_trunc', diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts index abc750837e16b..d577d9c73021d 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts @@ -70,6 +70,7 @@ import { buildOptionDefinition, buildSettingDefinitions, buildValueDefinitions, + getDateLiterals, buildFieldsDefinitionsWithMetadata, } from './factories'; import { EDITOR_MARKER, SINGLE_BACKTICK, METADATA_FIELDS } from '../shared/constants'; @@ -1086,7 +1087,11 @@ async function getFieldsOrFunctionsSuggestions( } } + // could also be in stats (bucket) but our autocomplete is not great yet + const displayDateSuggestions = types.includes('date') && ['where', 'eval'].includes(commandName); + const suggestions = filteredFieldsByType.concat( + displayDateSuggestions ? getDateLiterals() : [], functions ? getCompatibleFunctionDefinition(commandName, optionName, types, ignoreFn) : [], variables ? pushItUpInTheList(buildVariablesDefinitions(filteredVariablesByType), functions) @@ -1326,7 +1331,7 @@ async function getFunctionArgsSuggestions( return suggestions.map(({ text, ...rest }) => ({ ...rest, - text: addCommaIf(hasMoreMandatoryArgs && fnDefinition.type !== 'builtin', text), + text: addCommaIf(hasMoreMandatoryArgs && fnDefinition.type !== 'builtin' && text !== '', text), })); } @@ -1541,7 +1546,14 @@ async function getOptionArgsSuggestions( if (option.name === 'metadata') { const existingFields = new Set(option.args.filter(isColumnItem).map(({ name }) => name)); const filteredMetaFields = METADATA_FIELDS.filter((name) => !existingFields.has(name)); - suggestions.push(...buildFieldsDefinitions(filteredMetaFields)); + if (isNewExpression) { + suggestions.push(...buildFieldsDefinitions(filteredMetaFields)); + } else if (existingFields.size > 0) { + if (filteredMetaFields.length > 0) { + suggestions.push(commaCompleteItem); + } + suggestions.push(pipeCompleteItem); + } } if (command.name === 'stats') { diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts index b80e30f9d8fb0..f7075e955c1ef 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts @@ -28,6 +28,8 @@ const allFunctions = statsAggregationFunctionDefinitions .concat(evalFunctionDefinitions) .concat(groupingFunctionDefinitions); +export const TIME_SYSTEM_PARAMS = ['?earliest', '?latest']; + export const TRIGGER_SUGGESTION_COMMAND = { title: 'Trigger Suggestion Dialog', id: 'editor.action.triggerSuggest', @@ -198,7 +200,8 @@ export const buildSourcesDefinitions = ( export const buildConstantsDefinitions = ( userConstants: string[], - detail?: string + detail?: string, + sortText?: string ): SuggestionRawDefinition[] => userConstants.map((label) => ({ label, @@ -209,7 +212,7 @@ export const buildConstantsDefinitions = ( i18n.translate('kbn-esql-validation-autocomplete.esql.autocomplete.constantDefinition', { defaultMessage: `Constant`, }), - sortText: 'A', + sortText: sortText ?? 'A', })); export const buildValueDefinitions = ( @@ -389,3 +392,13 @@ export function getCompatibleLiterals(commandName: string, types: string[], name } return suggestions; } + +export function getDateLiterals() { + return buildConstantsDefinitions( + TIME_SYSTEM_PARAMS, + i18n.translate('kbn-esql-validation-autocomplete.esql.autocomplete.namedParamDefinition', { + defaultMessage: 'Named parameter', + }), + '1A' + ); +} diff --git a/packages/kbn-field-utils/src/components/field_description/field_description.test.tsx b/packages/kbn-field-utils/src/components/field_description/field_description.test.tsx index 55474f0fb5af3..c7670d16d4995 100644 --- a/packages/kbn-field-utils/src/components/field_description/field_description.test.tsx +++ b/packages/kbn-field-utils/src/components/field_description/field_description.test.tsx @@ -9,17 +9,18 @@ import React from 'react'; import { FieldDescription } from './field_description'; import { render, screen } from '@testing-library/react'; +import { FieldsMetadataPublicStart } from '@kbn/fields-metadata-plugin/public'; describe('FieldDescription', () => { it('should render correctly when no custom description', async () => { - render(); + render(); const desc = screen.queryByTestId('fieldDescription-bytes'); expect(desc).toBeNull(); }); it('should render correctly with a short custom description', async () => { const customDescription = 'test this desc'; - render(); + render(); const desc = screen.queryByTestId('fieldDescription-bytes'); expect(desc).toHaveTextContent(customDescription); const button = screen.queryByTestId('toggleFieldDescription-bytes'); @@ -28,7 +29,7 @@ describe('FieldDescription', () => { it('should render correctly with a long custom description', async () => { const customDescription = 'test this long desc '.repeat(8).trim(); - render(); + render(); expect(screen.queryByTestId('fieldDescription-bytes')).toHaveTextContent(customDescription); screen.queryByTestId('toggleFieldDescription-bytes')?.click(); expect(screen.queryByTestId('fieldDescription-bytes')).toHaveTextContent( @@ -40,9 +41,106 @@ describe('FieldDescription', () => { it('should render a long custom description without truncation', async () => { const customDescription = 'test this long desc '.repeat(8).trim(); - render(); + render( + + ); expect(screen.queryByTestId('fieldDescription-bytes')).toHaveTextContent(customDescription); const button = screen.queryByTestId('toggleFieldDescription-bytes'); expect(button).toBeNull(); }); + + it('should render correctly with markdown', async () => { + const fieldsMetadataService: Partial = { + useFieldsMetadata: jest.fn(() => ({ + fieldsMetadata: { + bytes: { description: 'ESC desc', type: 'long' }, + }, + loading: false, + error: undefined, + reload: jest.fn(), + })), + }; + const customDescription = 'test this `markdown` desc'; + render( + + ); + const desc = screen.queryByTestId('fieldDescription-bytes'); + expect(desc).toHaveTextContent('test this markdown desc'); + expect(fieldsMetadataService.useFieldsMetadata).not.toHaveBeenCalled(); + }); + + it('should fetch ECS metadata', async () => { + const fieldsMetadataService: Partial = { + useFieldsMetadata: jest.fn(() => ({ + fieldsMetadata: { + bytes: { description: 'ESC desc', type: 'long' }, + }, + loading: false, + error: undefined, + reload: jest.fn(), + })), + }; + render( + + ); + const desc = screen.queryByTestId('fieldDescription-bytes'); + expect(desc).toHaveTextContent('ESC desc'); + expect(fieldsMetadataService.useFieldsMetadata).toHaveBeenCalledWith({ + attributes: ['description', 'type'], + fieldNames: ['bytes'], + }); + }); + + it('should not show ECS metadata if types do not match', async () => { + const fieldsMetadataService: Partial = { + useFieldsMetadata: jest.fn(() => ({ + fieldsMetadata: { + bytes: { description: 'ESC desc', type: 'keyword' }, + }, + loading: false, + error: undefined, + reload: jest.fn(), + })), + }; + render( + + ); + const desc = screen.queryByTestId('fieldDescription-bytes'); + expect(desc).toBeNull(); + }); + + it('should not show ECS metadata if none found', async () => { + const fieldsMetadataService: Partial = { + useFieldsMetadata: jest.fn(() => ({ + fieldsMetadata: {}, + loading: false, + error: undefined, + reload: jest.fn(), + })), + }; + render( + + ); + const desc = screen.queryByTestId('fieldDescription-extension.keyword'); + expect(desc).toBeNull(); + expect(fieldsMetadataService.useFieldsMetadata).toHaveBeenCalledWith({ + attributes: ['description', 'type'], + fieldNames: ['extension'], + }); + }); }); diff --git a/packages/kbn-field-utils/src/components/field_description/field_description.tsx b/packages/kbn-field-utils/src/components/field_description/field_description.tsx index 5991106b806a8..b17fa7e856c86 100644 --- a/packages/kbn-field-utils/src/components/field_description/field_description.tsx +++ b/packages/kbn-field-utils/src/components/field_description/field_description.tsx @@ -8,27 +8,81 @@ import React, { useState } from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiText, EuiButtonEmpty, EuiTextBlockTruncate, useEuiTheme } from '@elastic/eui'; +import { Markdown } from '@kbn/shared-ux-markdown'; +import { + EuiText, + EuiButtonEmpty, + EuiTextBlockTruncate, + EuiSkeletonText, + useEuiTheme, +} from '@elastic/eui'; import { css } from '@emotion/react'; +import type { FieldsMetadataPublicStart } from '@kbn/fields-metadata-plugin/public'; +import { esFieldTypeToKibanaFieldType } from '@kbn/field-types'; const MAX_VISIBLE_LENGTH = 110; -export interface FieldDescriptionProps { +const removeKeywordSuffix = (name: string) => { + return name.endsWith('.keyword') ? name.slice(0, -8) : name; +}; + +export interface FieldDescriptionContentProps { field: { name: string; customDescription?: string; + type: string; }; color?: 'subdued'; truncate?: boolean; + Wrapper?: React.FC<{ children: React.ReactNode }>; +} + +export interface FieldDescriptionProps extends FieldDescriptionContentProps { + fieldsMetadataService?: FieldsMetadataPublicStart; } export const FieldDescription: React.FC = ({ - field, - color, - truncate = true, + fieldsMetadataService, + ...props }) => { + if (fieldsMetadataService && !props.field.customDescription) { + return ; + } + + return ; +}; + +const EcsFieldDescriptionFallback: React.FC< + FieldDescriptionProps & { fieldsMetadataService: FieldsMetadataPublicStart } +> = ({ fieldsMetadataService, ...props }) => { + const fieldName = removeKeywordSuffix(props.field.name); + const { fieldsMetadata, loading } = fieldsMetadataService.useFieldsMetadata({ + attributes: ['description', 'type'], + fieldNames: [fieldName], + }); + + const escFieldDescription = fieldsMetadata?.[fieldName]?.description; + const escFieldType = fieldsMetadata?.[fieldName]?.type; + + return ( + + + + ); +}; + +export const FieldDescriptionContent: React.FC< + FieldDescriptionContentProps & { ecsFieldDescription?: string } +> = ({ field, color, truncate = true, ecsFieldDescription, Wrapper }) => { const { euiTheme } = useEuiTheme(); - const customDescription = (field?.customDescription || '').trim(); + const customDescription = (field?.customDescription || ecsFieldDescription || '').trim(); const isTooLong = Boolean(truncate && customDescription.length > MAX_VISIBLE_LENGTH); const [isTruncated, setIsTruncated] = useState(isTooLong); @@ -36,7 +90,7 @@ export const FieldDescription: React.FC = ({ return null; } - return ( + const result = (
{isTruncated ? ( @@ -61,13 +115,15 @@ export const FieldDescription: React.FC = ({ } `} > - {customDescription} + + {customDescription} + ) : ( <> - {customDescription} + {customDescription} {isTooLong && ( = ({ )}
); + + return Wrapper ? {result} : result; }; diff --git a/packages/kbn-field-utils/tsconfig.json b/packages/kbn-field-utils/tsconfig.json index 9ac5ba7e942bc..5434723e4fd6a 100644 --- a/packages/kbn-field-utils/tsconfig.json +++ b/packages/kbn-field-utils/tsconfig.json @@ -11,6 +11,8 @@ "@kbn/field-types", "@kbn/expressions-plugin", "@kbn/data-view-utils", + "@kbn/fields-metadata-plugin", + "@kbn/shared-ux-markdown", ], "exclude": ["target/**/*"] } diff --git a/packages/kbn-guided-onboarding/src/components/landing_page/guide/guide_cards.constants.tsx b/packages/kbn-guided-onboarding/src/components/landing_page/guide/guide_cards.constants.tsx index 53b6b4bd5d9ee..ab9bd7db53f0c 100644 --- a/packages/kbn-guided-onboarding/src/components/landing_page/guide/guide_cards.constants.tsx +++ b/packages/kbn-guided-onboarding/src/components/landing_page/guide/guide_cards.constants.tsx @@ -163,7 +163,10 @@ export const guideCards: GuideCardConstants[] = [ defaultMessage: 'Monitor Kubernetes clusters', } ), - guideId: 'kubernetes', + navigateTo: { + appId: 'observabilityOnboarding', + path: '/kubernetes', + }, telemetryId: 'onboarding--observability--kubernetes', order: 11, }, diff --git a/packages/kbn-journeys/journey/journey_config.ts b/packages/kbn-journeys/journey/journey_config.ts index 98b39b8ce37ab..191fa83ee110e 100644 --- a/packages/kbn-journeys/journey/journey_config.ts +++ b/packages/kbn-journeys/journey/journey_config.ts @@ -142,6 +142,11 @@ export interface JourneyConfigOptions; + + /** + * Take browser page screenshot on every step complete + */ + takeScreenshotOnSuccess?: boolean; } export class JourneyConfig { @@ -219,4 +224,8 @@ export class JourneyConfig { getSynthtraceConfig() { return this.#opts.synthtrace; } + + takeScreenshotOnSuccess() { + return !!this.#opts.takeScreenshotOnSuccess; + } } diff --git a/packages/kbn-journeys/journey/journey_ftr_harness.ts b/packages/kbn-journeys/journey/journey_ftr_harness.ts index 7339b7ffbca01..86d6c9f09950b 100644 --- a/packages/kbn-journeys/journey/journey_ftr_harness.ts +++ b/packages/kbn-journeys/journey/journey_ftr_harness.ts @@ -305,17 +305,37 @@ export class JourneyFtrHarness { ]); } + private async takeScreenshots(page: Page) { + let screenshot; + let fs; + // screenshots taking might crash the browser + try { + screenshot = await page.screenshot({ animations: 'disabled' }); + fs = await page.screenshot({ animations: 'disabled', fullPage: true }); + } catch (e) { + if (!screenshot) { + this.log.error(`Failed to take screenshot of the visible viewport: ${e.message}`); + } else if (screenshot && !fs) { + this.log.error(`Failed to take screenshot of the full scrollable page: ${e.message}`); + } else { + this.log.error(`Unknown error on taking screenshots`); + } + } + + return { screenshot, fs }; + } + private async onStepSuccess(step: AnyStep) { if (!this.page) { return; } - const [screenshot, fs] = await Promise.all([ - this.page.screenshot(), - this.page.screenshot({ fullPage: true }), - ]); - - await this.screenshots.addSuccess(step, screenshot, fs); + if (this.journeyConfig.takeScreenshotOnSuccess()) { + const { screenshot, fs } = await this.takeScreenshots(this.page); + if (screenshot && fs) { + await this.screenshots.addSuccess(step, screenshot, fs); + } + } } private async onStepError(step: AnyStep, err: Error) { @@ -325,12 +345,10 @@ export class JourneyFtrHarness { } if (this.page) { - const [screenshot, fs] = await Promise.all([ - this.page.screenshot(), - this.page.screenshot({ fullPage: true }), - ]); - - await this.screenshots.addError(step, screenshot, fs); + const { screenshot, fs } = await this.takeScreenshots(this.page); + if (screenshot && fs) { + await this.screenshots.addError(step, screenshot, fs); + } } } diff --git a/packages/kbn-mock-idp-plugin/public/login_page.tsx b/packages/kbn-mock-idp-plugin/public/login_page.tsx index 83fff68408000..62e01e0f16324 100644 --- a/packages/kbn-mock-idp-plugin/public/login_page.tsx +++ b/packages/kbn-mock-idp-plugin/public/login_page.tsx @@ -139,6 +139,7 @@ export const LoginPage = () => { actions={[ ({ // values ...buildRuleGroup( - ['quoted_string', 'integer_literal', 'decimal_literal'], + ['quoted_string', 'integer_literal', 'decimal_literal', 'named_or_positional_param'], euiThemeVars.euiColorSuccessText ), ], diff --git a/packages/kbn-search-api-panels/components/github_link.tsx b/packages/kbn-search-api-panels/components/github_link.tsx index 9f5a2ee700c1b..74fbf84640582 100644 --- a/packages/kbn-search-api-panels/components/github_link.tsx +++ b/packages/kbn-search-api-panels/components/github_link.tsx @@ -14,7 +14,8 @@ export const GithubLink: React.FC<{ assetBasePath: string; label: string; href: string; -}> = ({ assetBasePath, label, href }) => { + 'aria-label'?: string; +}> = ({ assetBasePath, label, href, 'aria-label': ariaLabel }) => { return ( @@ -22,7 +23,7 @@ export const GithubLink: React.FC<{ - + {label} diff --git a/packages/kbn-search-api-panels/components/ingestions_panel.tsx b/packages/kbn-search-api-panels/components/ingestions_panel.tsx index ef9a0ef95ad09..953ac413e80fe 100644 --- a/packages/kbn-search-api-panels/components/ingestions_panel.tsx +++ b/packages/kbn-search-api-panels/components/ingestions_panel.tsx @@ -41,6 +41,12 @@ export const IngestionsPanel: React.FC = ({ links: [ { href: docLinks.logstash, + ariaLabel: i18n.translate( + 'searchApiPanels.welcomeBanner.ingestData.alternativeOptions.logstashDocumentation.ariaLabel', + { + defaultMessage: 'Logstash documentation', + } + ), label: i18n.translate( 'searchApiPanels.welcomeBanner.ingestData.alternativeOptions.logstashDocumentationLabel', { @@ -72,6 +78,12 @@ export const IngestionsPanel: React.FC = ({ links: [ { href: docLinks.beats, + ariaLabel: i18n.translate( + 'searchApiPanels.welcomeBanner.ingestData.alternativeOptions.beatsDocumentation.ariaLabel', + { + defaultMessage: 'Beats documentation', + } + ), label: i18n.translate( 'searchApiPanels.welcomeBanner.ingestData.alternativeOptions.beatsDocumentationLabel', { @@ -109,12 +121,17 @@ export const IngestionsPanel: React.FC = ({ {links && links.length > 0 && ( <> - {links.map(({ label, href, isGithubLink }, linksIndex) => ( + {links.map(({ label, href, isGithubLink, ariaLabel }, linksIndex) => ( {isGithubLink ? ( - + ) : ( - + {label} )} diff --git a/packages/kbn-search-api-panels/components/preprocess_data.tsx b/packages/kbn-search-api-panels/components/preprocess_data.tsx index d1c10c5218ba1..776fb4c214666 100644 --- a/packages/kbn-search-api-panels/components/preprocess_data.tsx +++ b/packages/kbn-search-api-panels/components/preprocess_data.tsx @@ -73,7 +73,16 @@ export const PreprocessDataPanel: React.FC<{

- + {i18n.translate( 'searchApiPanels.preprocessData.overview.dataEnrichment.learnMore', { @@ -109,7 +118,16 @@ export const PreprocessDataPanel: React.FC<{

- + {i18n.translate( 'searchApiPanels.preprocessData.overview.dataFiltering.learnMore', { @@ -147,7 +165,16 @@ export const PreprocessDataPanel: React.FC<{

- + {i18n.translate( 'searchApiPanels.preprocessData.overview.arrayJsonHandling.learnMore', { @@ -186,7 +213,16 @@ export const PreprocessDataPanel: React.FC<{

- + {i18n.translate( 'searchApiPanels.preprocessData.overview.dataTransformation.learnMore', { @@ -225,7 +261,16 @@ export const PreprocessDataPanel: React.FC<{

- + {i18n.translate( 'searchApiPanels.preprocessData.overview.pipelineHandling.learnMore', { diff --git a/packages/kbn-search-connectors/types/native_connectors.ts b/packages/kbn-search-connectors/types/native_connectors.ts index b48e069b1c78f..ea9bf34e3e448 100644 --- a/packages/kbn-search-connectors/types/native_connectors.ts +++ b/packages/kbn-search-connectors/types/native_connectors.ts @@ -4634,6 +4634,252 @@ export const NATIVE_CONNECTOR_DEFINITIONS: Record- + Exceptions API allows you to manage detection rule exceptions to prevent a + rule from generating an alert from incoming events even when the rule's + other criteria are met. + title: Security Solution Exceptions API (Elastic Cloud and self-hosted) + version: '2023-10-31' +servers: + - url: 'http://{kibana_host}:{port}' + variables: + kibana_host: + default: localhost + port: + default: '5601' +paths: + '/api/detection_engine/rules/{id}/exceptions': + post: + operationId: CreateRuleExceptionListItems + parameters: + - description: Detection rule's identifier + in: path + name: id + required: true + schema: + $ref: '#/components/schemas/RuleId' + requestBody: + content: + application/json: + schema: + type: object + properties: + items: + items: + $ref: '#/components/schemas/CreateRuleExceptionListItemProps' + type: array + required: + - items + description: Rule exception list items + required: true + responses: + '200': + content: + application/json: + schema: + items: + $ref: '#/components/schemas/ExceptionListItem' + type: array + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Creates rule exception list items + tags: + - Exceptions API + /api/exception_lists: + delete: + operationId: DeleteExceptionList + parameters: + - description: Either `id` or `list_id` must be specified + in: query + name: id + required: false + schema: + $ref: '#/components/schemas/ExceptionListId' + - description: Either `id` or `list_id` must be specified + in: query + name: list_id + required: false + schema: + $ref: '#/components/schemas/ExceptionListHumanId' + - in: query + name: namespace_type + required: false + schema: + $ref: '#/components/schemas/ExceptionNamespaceType' + default: single + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ExceptionList' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Exception list not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Deletes an exception list + tags: + - Exceptions API + get: + operationId: GetExceptionList + parameters: + - description: Either `id` or `list_id` must be specified + in: query + name: id + required: false + schema: + $ref: '#/components/schemas/ExceptionListId' + - description: Either `id` or `list_id` must be specified + in: query + name: list_id + required: false + schema: + $ref: '#/components/schemas/ExceptionListHumanId' + - in: query + name: namespace_type + required: false + schema: + $ref: '#/components/schemas/ExceptionNamespaceType' + default: single + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ExceptionList' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Exception list item not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Retrieves an exception list using its `id` or `list_id` field + tags: + - Exceptions API + post: + operationId: CreateExceptionList + requestBody: + content: + application/json: + schema: + type: object + properties: + description: + $ref: '#/components/schemas/ExceptionListDescription' + list_id: + $ref: '#/components/schemas/ExceptionListHumanId' + meta: + $ref: '#/components/schemas/ExceptionListMeta' + name: + $ref: '#/components/schemas/ExceptionListName' + namespace_type: + $ref: '#/components/schemas/ExceptionNamespaceType' + default: single + os_types: + $ref: '#/components/schemas/ExceptionListOsTypeArray' + tags: + $ref: '#/components/schemas/ExceptionListTags' + default: [] + type: + $ref: '#/components/schemas/ExceptionListType' + version: + $ref: '#/components/schemas/ExceptionListVersion' + default: 1 + required: + - name + - description + - type + description: Exception list's properties + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ExceptionList' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '409': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Exception list already exists response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Creates an exception list + tags: + - Exceptions API + put: + operationId: UpdateExceptionList + requestBody: + content: + application/json: + schema: + type: object + properties: + _version: + type: string + description: + $ref: '#/components/schemas/ExceptionListDescription' + id: + $ref: '#/components/schemas/ExceptionListId' + list_id: + $ref: '#/components/schemas/ExceptionListHumanId' + meta: + $ref: '#/components/schemas/ExceptionListMeta' + name: + $ref: '#/components/schemas/ExceptionListName' + namespace_type: + $ref: '#/components/schemas/ExceptionNamespaceType' + default: single + os_types: + $ref: '#/components/schemas/ExceptionListOsTypeArray' + default: [] + tags: + $ref: '#/components/schemas/ExceptionListTags' + type: + $ref: '#/components/schemas/ExceptionListType' + version: + $ref: '#/components/schemas/ExceptionListVersion' + required: + - name + - description + - type + description: Exception list's properties + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ExceptionList' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Exception list not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Updates an exception list + tags: + - Exceptions API + /api/exception_lists/_duplicate: + post: + operationId: DuplicateExceptionList + parameters: + - description: Exception list's human identifier + in: query + name: list_id + required: true + schema: + $ref: '#/components/schemas/ExceptionListHumanId' + - in: query + name: namespace_type + required: true + schema: + $ref: '#/components/schemas/ExceptionNamespaceType' + - description: >- + Determines whether to include expired exceptions in the exported + list + in: query + name: include_expired_exceptions + required: true + schema: + default: 'true' + enum: + - 'true' + - 'false' + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ExceptionList' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '405': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Exception list to duplicate not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Duplicates an exception list + tags: + - Exceptions API + /api/exception_lists/_export: + post: + description: Exports an exception list and its associated items to an .ndjson file + operationId: ExportExceptionList + parameters: + - description: Exception list's identifier + in: query + name: id + required: true + schema: + $ref: '#/components/schemas/ExceptionListId' + - description: Exception list's human identifier + in: query + name: list_id + required: true + schema: + $ref: '#/components/schemas/ExceptionListHumanId' + - in: query + name: namespace_type + required: true + schema: + $ref: '#/components/schemas/ExceptionNamespaceType' + - description: >- + Determines whether to include expired exceptions in the exported + list + in: query + name: include_expired_exceptions + required: true + schema: + default: 'true' + enum: + - 'true' + - 'false' + type: string + responses: + '200': + content: + application/ndjson: + schema: + description: >- + A `.ndjson` file containing specified exception list and its + items + format: binary + type: string + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Exception list not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Exports an exception list + tags: + - Exceptions API + /api/exception_lists/_find: + get: + operationId: FindExceptionLists + parameters: + - description: > + Filters the returned results according to the value of the specified + field. + + + Uses the `so type.field name:field` value syntax, where `so type` + can be: + + + - `exception-list`: Specify a space-aware exception list. + + - `exception-list-agnostic`: Specify an exception list that is + shared across spaces. + in: query + name: filter + required: false + schema: + $ref: '#/components/schemas/FindExceptionListsFilter' + - description: > + Determines whether the returned containers are Kibana associated + with a Kibana space + + or available in all spaces (`agnostic` or `single`) + in: query + name: namespace_type + required: false + schema: + default: + - single + items: + $ref: '#/components/schemas/ExceptionNamespaceType' + type: array + - description: The page number to return + in: query + name: page + required: false + schema: + minimum: 1 + type: integer + - description: The number of exception lists to return per page + in: query + name: per_page + required: false + schema: + minimum: 1 + type: integer + - description: Determines which field is used to sort the results + in: query + name: sort_field + required: false + schema: + type: string + - description: 'Determines the sort order, which can be `desc` or `asc`' + in: query + name: sort_order + required: false + schema: + enum: + - desc + - asc + type: string + responses: + '200': + content: + application/json: + schema: + type: object + properties: + data: + items: + $ref: '#/components/schemas/ExceptionList' + type: array + page: + minimum: 1 + type: integer + per_page: + minimum: 1 + type: integer + total: + minimum: 0 + type: integer + required: + - data + - page + - per_page + - total + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Finds exception lists + tags: + - Exceptions API + /api/exception_lists/_import: + post: + description: Imports an exception list and associated items + operationId: ImportExceptionList + parameters: + - description: > + Determines whether existing exception lists with the same `list_id` + are overwritten. + + If any exception items have the same `item_id`, those are also + overwritten. + in: query + name: overwrite + required: false + schema: + default: false + type: boolean + - in: query + name: overwrite_exceptions + required: false + schema: + default: false + type: boolean + - in: query + name: overwrite_action_connectors + required: false + schema: + default: false + type: boolean + - description: > + Determines whether the list being imported will have a new `list_id` + generated. + + Additional `item_id`'s are generated for each exception item. Both + the exception + + list and its items are overwritten. + in: query + name: as_new_list + required: false + schema: + default: false + type: boolean + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + file: + description: A `.ndjson` file containing the exception list + format: binary + type: string + required: true + responses: + '200': + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/ExceptionListsImportBulkErrorArray' + success: + type: boolean + success_count: + minimum: 0 + type: integer + success_count_exception_list_items: + minimum: 0 + type: integer + success_count_exception_lists: + minimum: 0 + type: integer + success_exception_list_items: + type: boolean + success_exception_lists: + type: boolean + required: + - errors + - success + - success_count + - success_exception_lists + - success_count_exception_lists + - success_exception_list_items + - success_count_exception_list_items + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Imports an exception list + tags: + - Exceptions API + /api/exception_lists/items: + delete: + operationId: DeleteExceptionListItem + parameters: + - description: Either `id` or `item_id` must be specified + in: query + name: id + required: false + schema: + $ref: '#/components/schemas/ExceptionListItemId' + - description: Either `id` or `item_id` must be specified + in: query + name: item_id + required: false + schema: + $ref: '#/components/schemas/ExceptionListItemHumanId' + - in: query + name: namespace_type + required: false + schema: + $ref: '#/components/schemas/ExceptionNamespaceType' + default: single + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ExceptionListItem' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Exception list item not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Deletes an exception list item + tags: + - Exceptions API + get: + operationId: GetExceptionListItem + parameters: + - description: Either `id` or `item_id` must be specified + in: query + name: id + required: false + schema: + $ref: '#/components/schemas/ExceptionListItemId' + - description: Either `id` or `item_id` must be specified + in: query + name: item_id + required: false + schema: + $ref: '#/components/schemas/ExceptionListItemHumanId' + - in: query + name: namespace_type + required: false + schema: + $ref: '#/components/schemas/ExceptionNamespaceType' + default: single + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ExceptionListItem' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Exception list item not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Gets an exception list item + tags: + - Exceptions API + post: + operationId: CreateExceptionListItem + requestBody: + content: + application/json: + schema: + type: object + properties: + comments: + $ref: '#/components/schemas/CreateExceptionListItemCommentArray' + default: [] + description: + $ref: '#/components/schemas/ExceptionListItemDescription' + entries: + $ref: '#/components/schemas/ExceptionListItemEntryArray' + expire_time: + format: date-time + type: string + item_id: + $ref: '#/components/schemas/ExceptionListItemHumanId' + list_id: + $ref: '#/components/schemas/ExceptionListHumanId' + meta: + $ref: '#/components/schemas/ExceptionListItemMeta' + name: + $ref: '#/components/schemas/ExceptionListItemName' + namespace_type: + $ref: '#/components/schemas/ExceptionNamespaceType' + default: single + os_types: + $ref: '#/components/schemas/ExceptionListItemOsTypeArray' + default: [] + tags: + $ref: '#/components/schemas/ExceptionListItemTags' + default: [] + type: + $ref: '#/components/schemas/ExceptionListItemType' + required: + - list_id + - type + - name + - description + - entries + description: Exception list item's properties + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ExceptionListItem' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '409': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Exception list item already exists response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Creates an exception list item + tags: + - Exceptions API + put: + operationId: UpdateExceptionListItem + requestBody: + content: + application/json: + schema: + type: object + properties: + _version: + type: string + comments: + $ref: '#/components/schemas/UpdateExceptionListItemCommentArray' + default: [] + description: + $ref: '#/components/schemas/ExceptionListItemDescription' + entries: + $ref: '#/components/schemas/ExceptionListItemEntryArray' + expire_time: + format: date-time + type: string + id: + $ref: '#/components/schemas/ExceptionListItemId' + description: Either `id` or `item_id` must be specified + item_id: + $ref: '#/components/schemas/ExceptionListItemHumanId' + description: Either `id` or `item_id` must be specified + list_id: + $ref: '#/components/schemas/ExceptionListHumanId' + meta: + $ref: '#/components/schemas/ExceptionListItemMeta' + name: + $ref: '#/components/schemas/ExceptionListItemName' + namespace_type: + $ref: '#/components/schemas/ExceptionNamespaceType' + default: single + os_types: + $ref: '#/components/schemas/ExceptionListItemOsTypeArray' + default: [] + tags: + $ref: '#/components/schemas/ExceptionListItemTags' + type: + $ref: '#/components/schemas/ExceptionListItemType' + required: + - type + - name + - description + - entries + description: Exception list item's properties + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ExceptionListItem' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Exception list item not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Updates an exception list item + tags: + - Exceptions API + /api/exception_lists/items/_find: + get: + operationId: FindExceptionListItems + parameters: + - description: List's id + in: query + name: list_id + required: true + schema: + items: + $ref: '#/components/schemas/ExceptionListHumanId' + type: array + - description: > + Filters the returned results according to the value of the specified + field, + + using the `:` syntax. + in: query + name: filter + required: false + schema: + default: [] + items: + $ref: '#/components/schemas/FindExceptionListItemsFilter' + type: array + - description: > + Determines whether the returned containers are Kibana associated + with a Kibana space + + or available in all spaces (`agnostic` or `single`) + in: query + name: namespace_type + required: false + schema: + default: + - single + items: + $ref: '#/components/schemas/ExceptionNamespaceType' + type: array + - in: query + name: search + required: false + schema: + type: string + - description: The page number to return + in: query + name: page + required: false + schema: + minimum: 0 + type: integer + - description: The number of exception list items to return per page + in: query + name: per_page + required: false + schema: + minimum: 0 + type: integer + - description: Determines which field is used to sort the results + in: query + name: sort_field + required: false + schema: + $ref: '#/components/schemas/NonEmptyString' + - description: 'Determines the sort order, which can be `desc` or `asc`' + in: query + name: sort_order + required: false + schema: + enum: + - desc + - asc + type: string + responses: + '200': + content: + application/json: + schema: + type: object + properties: + data: + items: + $ref: '#/components/schemas/ExceptionListItem' + type: array + page: + minimum: 1 + type: integer + per_page: + minimum: 1 + type: integer + pit: + type: string + total: + minimum: 0 + type: integer + required: + - data + - page + - per_page + - total + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Exception list not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Finds exception list items + tags: + - Exceptions API + /api/exception_lists/summary: + get: + operationId: GetExceptionListSummary + parameters: + - description: Exception list's identifier generated upon creation + in: query + name: id + required: false + schema: + $ref: '#/components/schemas/ExceptionListId' + - description: Exception list's human readable identifier + in: query + name: list_id + required: false + schema: + $ref: '#/components/schemas/ExceptionListHumanId' + - in: query + name: namespace_type + required: false + schema: + $ref: '#/components/schemas/ExceptionNamespaceType' + default: single + - description: Search filter clause + in: query + name: filter + required: false + schema: + type: string + responses: + '200': + content: + application/json: + schema: + type: object + properties: + linux: + minimum: 0 + type: integer + macos: + minimum: 0 + type: integer + total: + minimum: 0 + type: integer + windows: + minimum: 0 + type: integer + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Exception list not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Retrieves an exception list summary + tags: + - Exceptions API + /api/exceptions/shared: + post: + operationId: CreateSharedExceptionList + requestBody: + content: + application/json: + schema: + type: object + properties: + description: + $ref: '#/components/schemas/ExceptionListDescription' + name: + $ref: '#/components/schemas/ExceptionListName' + required: + - name + - description + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ExceptionList' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '409': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Exception list already exists response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Creates a shared exception list + tags: + - Exceptions API +components: + schemas: + CreateExceptionListItemComment: + type: object + properties: + comment: + $ref: '#/components/schemas/NonEmptyString' + required: + - comment + CreateExceptionListItemCommentArray: + items: + $ref: '#/components/schemas/CreateExceptionListItemComment' + type: array + CreateRuleExceptionListItemComment: + type: object + properties: + comment: + $ref: '#/components/schemas/NonEmptyString' + required: + - comment + CreateRuleExceptionListItemCommentArray: + items: + $ref: '#/components/schemas/CreateRuleExceptionListItemComment' + type: array + CreateRuleExceptionListItemProps: + type: object + properties: + comments: + $ref: '#/components/schemas/CreateRuleExceptionListItemCommentArray' + default: [] + description: + $ref: '#/components/schemas/ExceptionListItemDescription' + entries: + $ref: '#/components/schemas/ExceptionListItemEntryArray' + expire_time: + format: date-time + type: string + item_id: + $ref: '#/components/schemas/ExceptionListItemHumanId' + meta: + $ref: '#/components/schemas/ExceptionListItemMeta' + name: + $ref: '#/components/schemas/ExceptionListItemName' + namespace_type: + $ref: '#/components/schemas/ExceptionNamespaceType' + default: single + os_types: + $ref: '#/components/schemas/ExceptionListItemOsTypeArray' + default: [] + tags: + $ref: '#/components/schemas/ExceptionListItemTags' + default: [] + type: + $ref: '#/components/schemas/ExceptionListItemType' + required: + - type + - name + - description + - entries + ExceptionList: + type: object + properties: + _version: + type: string + created_at: + format: date-time + type: string + created_by: + type: string + description: + $ref: '#/components/schemas/ExceptionListDescription' + id: + $ref: '#/components/schemas/ExceptionListId' + immutable: + type: boolean + list_id: + $ref: '#/components/schemas/ExceptionListHumanId' + meta: + $ref: '#/components/schemas/ExceptionListMeta' + name: + $ref: '#/components/schemas/ExceptionListName' + namespace_type: + $ref: '#/components/schemas/ExceptionNamespaceType' + os_types: + $ref: '#/components/schemas/ExceptionListOsTypeArray' + tags: + $ref: '#/components/schemas/ExceptionListTags' + tie_breaker_id: + type: string + type: + $ref: '#/components/schemas/ExceptionListType' + updated_at: + format: date-time + type: string + updated_by: + type: string + version: + $ref: '#/components/schemas/ExceptionListVersion' + required: + - id + - list_id + - type + - name + - description + - immutable + - namespace_type + - version + - tie_breaker_id + - created_at + - created_by + - updated_at + - updated_by + ExceptionListDescription: + type: string + ExceptionListHumanId: + $ref: '#/components/schemas/NonEmptyString' + description: 'Human readable string identifier, e.g. `trusted-linux-processes`' + ExceptionListId: + $ref: '#/components/schemas/NonEmptyString' + ExceptionListItem: + type: object + properties: + _version: + type: string + comments: + $ref: '#/components/schemas/ExceptionListItemCommentArray' + created_at: + format: date-time + type: string + created_by: + type: string + description: + $ref: '#/components/schemas/ExceptionListItemDescription' + entries: + $ref: '#/components/schemas/ExceptionListItemEntryArray' + expire_time: + format: date-time + type: string + id: + $ref: '#/components/schemas/ExceptionListItemId' + item_id: + $ref: '#/components/schemas/ExceptionListItemHumanId' + list_id: + $ref: '#/components/schemas/ExceptionListHumanId' + meta: + $ref: '#/components/schemas/ExceptionListItemMeta' + name: + $ref: '#/components/schemas/ExceptionListItemName' + namespace_type: + $ref: '#/components/schemas/ExceptionNamespaceType' + os_types: + $ref: '#/components/schemas/ExceptionListItemOsTypeArray' + tags: + $ref: '#/components/schemas/ExceptionListItemTags' + tie_breaker_id: + type: string + type: + $ref: '#/components/schemas/ExceptionListItemType' + updated_at: + format: date-time + type: string + updated_by: + type: string + required: + - id + - item_id + - list_id + - type + - name + - description + - entries + - namespace_type + - comments + - tie_breaker_id + - created_at + - created_by + - updated_at + - updated_by + ExceptionListItemComment: + type: object + properties: + comment: + $ref: '#/components/schemas/NonEmptyString' + created_at: + format: date-time + type: string + created_by: + $ref: '#/components/schemas/NonEmptyString' + id: + $ref: '#/components/schemas/NonEmptyString' + updated_at: + format: date-time + type: string + updated_by: + $ref: '#/components/schemas/NonEmptyString' + required: + - id + - comment + - created_at + - created_by + ExceptionListItemCommentArray: + items: + $ref: '#/components/schemas/ExceptionListItemComment' + type: array + ExceptionListItemDescription: + type: string + ExceptionListItemEntry: + anyOf: + - $ref: '#/components/schemas/ExceptionListItemEntryMatch' + - $ref: '#/components/schemas/ExceptionListItemEntryMatchAny' + - $ref: '#/components/schemas/ExceptionListItemEntryList' + - $ref: '#/components/schemas/ExceptionListItemEntryExists' + - $ref: '#/components/schemas/ExceptionListItemEntryNested' + - $ref: '#/components/schemas/ExceptionListItemEntryMatchWildcard' + discriminator: + propertyName: type + ExceptionListItemEntryArray: + items: + $ref: '#/components/schemas/ExceptionListItemEntry' + type: array + ExceptionListItemEntryExists: + type: object + properties: + field: + $ref: '#/components/schemas/NonEmptyString' + operator: + $ref: '#/components/schemas/ExceptionListItemEntryOperator' + type: + enum: + - exists + type: string + required: + - type + - field + - operator + ExceptionListItemEntryList: + type: object + properties: + field: + $ref: '#/components/schemas/NonEmptyString' + list: + type: object + properties: + id: + $ref: '#/components/schemas/ListId' + type: + $ref: '#/components/schemas/ListType' + required: + - id + - type + operator: + $ref: '#/components/schemas/ExceptionListItemEntryOperator' + type: + enum: + - list + type: string + required: + - type + - field + - list + - operator + ExceptionListItemEntryMatch: + type: object + properties: + field: + $ref: '#/components/schemas/NonEmptyString' + operator: + $ref: '#/components/schemas/ExceptionListItemEntryOperator' + type: + enum: + - match + type: string + value: + $ref: '#/components/schemas/NonEmptyString' + required: + - type + - field + - value + - operator + ExceptionListItemEntryMatchAny: + type: object + properties: + field: + $ref: '#/components/schemas/NonEmptyString' + operator: + $ref: '#/components/schemas/ExceptionListItemEntryOperator' + type: + enum: + - match_any + type: string + value: + items: + $ref: '#/components/schemas/NonEmptyString' + minItems: 1 + type: array + required: + - type + - field + - value + - operator + ExceptionListItemEntryMatchWildcard: + type: object + properties: + field: + $ref: '#/components/schemas/NonEmptyString' + operator: + $ref: '#/components/schemas/ExceptionListItemEntryOperator' + type: + enum: + - wildcard + type: string + value: + $ref: '#/components/schemas/NonEmptyString' + required: + - type + - field + - value + - operator + ExceptionListItemEntryNested: + type: object + properties: + entries: + items: + $ref: '#/components/schemas/ExceptionListItemEntryNestedEntryItem' + minItems: 1 + type: array + field: + $ref: '#/components/schemas/NonEmptyString' + type: + enum: + - nested + type: string + required: + - type + - field + - entries + ExceptionListItemEntryNestedEntryItem: + oneOf: + - $ref: '#/components/schemas/ExceptionListItemEntryMatch' + - $ref: '#/components/schemas/ExceptionListItemEntryMatchAny' + - $ref: '#/components/schemas/ExceptionListItemEntryExists' + ExceptionListItemEntryOperator: + enum: + - excluded + - included + type: string + ExceptionListItemHumanId: + $ref: '#/components/schemas/NonEmptyString' + ExceptionListItemId: + $ref: '#/components/schemas/NonEmptyString' + ExceptionListItemMeta: + additionalProperties: true + type: object + ExceptionListItemName: + $ref: '#/components/schemas/NonEmptyString' + ExceptionListItemOsTypeArray: + items: + $ref: '#/components/schemas/ExceptionListOsType' + type: array + ExceptionListItemTags: + items: + $ref: '#/components/schemas/NonEmptyString' + type: array + ExceptionListItemType: + enum: + - simple + type: string + ExceptionListMeta: + additionalProperties: true + type: object + ExceptionListName: + type: string + ExceptionListOsType: + enum: + - linux + - macos + - windows + type: string + ExceptionListOsTypeArray: + items: + $ref: '#/components/schemas/ExceptionListOsType' + type: array + ExceptionListsImportBulkError: + type: object + properties: + error: + type: object + properties: + message: + type: string + status_code: + type: integer + required: + - status_code + - message + id: + $ref: '#/components/schemas/ExceptionListId' + item_id: + $ref: '#/components/schemas/ExceptionListItemHumanId' + list_id: + $ref: '#/components/schemas/ExceptionListHumanId' + required: + - error + ExceptionListsImportBulkErrorArray: + items: + $ref: '#/components/schemas/ExceptionListsImportBulkError' + type: array + ExceptionListTags: + items: + type: string + type: array + ExceptionListType: + enum: + - detection + - rule_default + - endpoint + - endpoint_trusted_apps + - endpoint_events + - endpoint_host_isolation_exceptions + - endpoint_blocklists + type: string + ExceptionListVersion: + minimum: 1 + type: integer + ExceptionNamespaceType: + description: > + Determines whether the exception container is available in all Kibana + spaces or just the space + + in which it is created, where: + + + - `single`: Only available in the Kibana space in which it is created. + + - `agnostic`: Available in all Kibana spaces. + enum: + - agnostic + - single + type: string + FindExceptionListItemsFilter: + $ref: '#/components/schemas/NonEmptyString' + FindExceptionListsFilter: + type: string + ListId: + $ref: '#/components/schemas/NonEmptyString' + ListType: + enum: + - binary + - boolean + - byte + - date + - date_nanos + - date_range + - double + - double_range + - float + - float_range + - geo_point + - geo_shape + - half_float + - integer + - integer_range + - ip + - ip_range + - keyword + - long + - long_range + - shape + - short + - text + type: string + NonEmptyString: + description: A string that is not empty and does not contain only whitespace + minLength: 1 + pattern: ^(?! *$).+$ + type: string + PlatformErrorResponse: + type: object + properties: + error: + type: string + message: + type: string + statusCode: + type: integer + required: + - statusCode + - error + - message + RuleId: + $ref: '#/components/schemas/UUID' + SiemErrorResponse: + type: object + properties: + message: + type: string + status_code: + type: integer + required: + - status_code + - message + UpdateExceptionListItemComment: + type: object + properties: + comment: + $ref: '#/components/schemas/NonEmptyString' + id: + $ref: '#/components/schemas/NonEmptyString' + required: + - comment + UpdateExceptionListItemCommentArray: + items: + $ref: '#/components/schemas/UpdateExceptionListItemComment' + type: array + UUID: + description: A universally unique identifier + format: uuid + type: string + securitySchemes: + BasicAuth: + scheme: basic + type: http +security: + - BasicAuth: [] +tags: ! '' diff --git a/packages/kbn-securitysolution-exceptions-common/docs/openapi/serverless/security_solution_exceptions_api_2023_10_31.bundled.schema.yaml b/packages/kbn-securitysolution-exceptions-common/docs/openapi/serverless/security_solution_exceptions_api_2023_10_31.bundled.schema.yaml new file mode 100644 index 0000000000000..43201d462f72e --- /dev/null +++ b/packages/kbn-securitysolution-exceptions-common/docs/openapi/serverless/security_solution_exceptions_api_2023_10_31.bundled.schema.yaml @@ -0,0 +1,1855 @@ +openapi: 3.0.3 +info: + description: >- + Exceptions API allows you to manage detection rule exceptions to prevent a + rule from generating an alert from incoming events even when the rule's + other criteria are met. + title: Security Solution Exceptions API (Elastic Cloud Serverless) + version: '2023-10-31' +servers: + - url: 'http://{kibana_host}:{port}' + variables: + kibana_host: + default: localhost + port: + default: '5601' +paths: + '/api/detection_engine/rules/{id}/exceptions': + post: + operationId: CreateRuleExceptionListItems + parameters: + - description: Detection rule's identifier + in: path + name: id + required: true + schema: + $ref: '#/components/schemas/RuleId' + requestBody: + content: + application/json: + schema: + type: object + properties: + items: + items: + $ref: '#/components/schemas/CreateRuleExceptionListItemProps' + type: array + required: + - items + description: Rule exception list items + required: true + responses: + '200': + content: + application/json: + schema: + items: + $ref: '#/components/schemas/ExceptionListItem' + type: array + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Creates rule exception list items + tags: + - Exceptions API + /api/exception_lists: + delete: + operationId: DeleteExceptionList + parameters: + - description: Either `id` or `list_id` must be specified + in: query + name: id + required: false + schema: + $ref: '#/components/schemas/ExceptionListId' + - description: Either `id` or `list_id` must be specified + in: query + name: list_id + required: false + schema: + $ref: '#/components/schemas/ExceptionListHumanId' + - in: query + name: namespace_type + required: false + schema: + $ref: '#/components/schemas/ExceptionNamespaceType' + default: single + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ExceptionList' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Exception list not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Deletes an exception list + tags: + - Exceptions API + get: + operationId: GetExceptionList + parameters: + - description: Either `id` or `list_id` must be specified + in: query + name: id + required: false + schema: + $ref: '#/components/schemas/ExceptionListId' + - description: Either `id` or `list_id` must be specified + in: query + name: list_id + required: false + schema: + $ref: '#/components/schemas/ExceptionListHumanId' + - in: query + name: namespace_type + required: false + schema: + $ref: '#/components/schemas/ExceptionNamespaceType' + default: single + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ExceptionList' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Exception list item not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Retrieves an exception list using its `id` or `list_id` field + tags: + - Exceptions API + post: + operationId: CreateExceptionList + requestBody: + content: + application/json: + schema: + type: object + properties: + description: + $ref: '#/components/schemas/ExceptionListDescription' + list_id: + $ref: '#/components/schemas/ExceptionListHumanId' + meta: + $ref: '#/components/schemas/ExceptionListMeta' + name: + $ref: '#/components/schemas/ExceptionListName' + namespace_type: + $ref: '#/components/schemas/ExceptionNamespaceType' + default: single + os_types: + $ref: '#/components/schemas/ExceptionListOsTypeArray' + tags: + $ref: '#/components/schemas/ExceptionListTags' + default: [] + type: + $ref: '#/components/schemas/ExceptionListType' + version: + $ref: '#/components/schemas/ExceptionListVersion' + default: 1 + required: + - name + - description + - type + description: Exception list's properties + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ExceptionList' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '409': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Exception list already exists response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Creates an exception list + tags: + - Exceptions API + put: + operationId: UpdateExceptionList + requestBody: + content: + application/json: + schema: + type: object + properties: + _version: + type: string + description: + $ref: '#/components/schemas/ExceptionListDescription' + id: + $ref: '#/components/schemas/ExceptionListId' + list_id: + $ref: '#/components/schemas/ExceptionListHumanId' + meta: + $ref: '#/components/schemas/ExceptionListMeta' + name: + $ref: '#/components/schemas/ExceptionListName' + namespace_type: + $ref: '#/components/schemas/ExceptionNamespaceType' + default: single + os_types: + $ref: '#/components/schemas/ExceptionListOsTypeArray' + default: [] + tags: + $ref: '#/components/schemas/ExceptionListTags' + type: + $ref: '#/components/schemas/ExceptionListType' + version: + $ref: '#/components/schemas/ExceptionListVersion' + required: + - name + - description + - type + description: Exception list's properties + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ExceptionList' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Exception list not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Updates an exception list + tags: + - Exceptions API + /api/exception_lists/_duplicate: + post: + operationId: DuplicateExceptionList + parameters: + - description: Exception list's human identifier + in: query + name: list_id + required: true + schema: + $ref: '#/components/schemas/ExceptionListHumanId' + - in: query + name: namespace_type + required: true + schema: + $ref: '#/components/schemas/ExceptionNamespaceType' + - description: >- + Determines whether to include expired exceptions in the exported + list + in: query + name: include_expired_exceptions + required: true + schema: + default: 'true' + enum: + - 'true' + - 'false' + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ExceptionList' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '405': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Exception list to duplicate not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Duplicates an exception list + tags: + - Exceptions API + /api/exception_lists/_export: + post: + description: Exports an exception list and its associated items to an .ndjson file + operationId: ExportExceptionList + parameters: + - description: Exception list's identifier + in: query + name: id + required: true + schema: + $ref: '#/components/schemas/ExceptionListId' + - description: Exception list's human identifier + in: query + name: list_id + required: true + schema: + $ref: '#/components/schemas/ExceptionListHumanId' + - in: query + name: namespace_type + required: true + schema: + $ref: '#/components/schemas/ExceptionNamespaceType' + - description: >- + Determines whether to include expired exceptions in the exported + list + in: query + name: include_expired_exceptions + required: true + schema: + default: 'true' + enum: + - 'true' + - 'false' + type: string + responses: + '200': + content: + application/ndjson: + schema: + description: >- + A `.ndjson` file containing specified exception list and its + items + format: binary + type: string + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Exception list not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Exports an exception list + tags: + - Exceptions API + /api/exception_lists/_find: + get: + operationId: FindExceptionLists + parameters: + - description: > + Filters the returned results according to the value of the specified + field. + + + Uses the `so type.field name:field` value syntax, where `so type` + can be: + + + - `exception-list`: Specify a space-aware exception list. + + - `exception-list-agnostic`: Specify an exception list that is + shared across spaces. + in: query + name: filter + required: false + schema: + $ref: '#/components/schemas/FindExceptionListsFilter' + - description: > + Determines whether the returned containers are Kibana associated + with a Kibana space + + or available in all spaces (`agnostic` or `single`) + in: query + name: namespace_type + required: false + schema: + default: + - single + items: + $ref: '#/components/schemas/ExceptionNamespaceType' + type: array + - description: The page number to return + in: query + name: page + required: false + schema: + minimum: 1 + type: integer + - description: The number of exception lists to return per page + in: query + name: per_page + required: false + schema: + minimum: 1 + type: integer + - description: Determines which field is used to sort the results + in: query + name: sort_field + required: false + schema: + type: string + - description: 'Determines the sort order, which can be `desc` or `asc`' + in: query + name: sort_order + required: false + schema: + enum: + - desc + - asc + type: string + responses: + '200': + content: + application/json: + schema: + type: object + properties: + data: + items: + $ref: '#/components/schemas/ExceptionList' + type: array + page: + minimum: 1 + type: integer + per_page: + minimum: 1 + type: integer + total: + minimum: 0 + type: integer + required: + - data + - page + - per_page + - total + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Finds exception lists + tags: + - Exceptions API + /api/exception_lists/_import: + post: + description: Imports an exception list and associated items + operationId: ImportExceptionList + parameters: + - description: > + Determines whether existing exception lists with the same `list_id` + are overwritten. + + If any exception items have the same `item_id`, those are also + overwritten. + in: query + name: overwrite + required: false + schema: + default: false + type: boolean + - in: query + name: overwrite_exceptions + required: false + schema: + default: false + type: boolean + - in: query + name: overwrite_action_connectors + required: false + schema: + default: false + type: boolean + - description: > + Determines whether the list being imported will have a new `list_id` + generated. + + Additional `item_id`'s are generated for each exception item. Both + the exception + + list and its items are overwritten. + in: query + name: as_new_list + required: false + schema: + default: false + type: boolean + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + file: + description: A `.ndjson` file containing the exception list + format: binary + type: string + required: true + responses: + '200': + content: + application/json: + schema: + type: object + properties: + errors: + $ref: '#/components/schemas/ExceptionListsImportBulkErrorArray' + success: + type: boolean + success_count: + minimum: 0 + type: integer + success_count_exception_list_items: + minimum: 0 + type: integer + success_count_exception_lists: + minimum: 0 + type: integer + success_exception_list_items: + type: boolean + success_exception_lists: + type: boolean + required: + - errors + - success + - success_count + - success_exception_lists + - success_count_exception_lists + - success_exception_list_items + - success_count_exception_list_items + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Imports an exception list + tags: + - Exceptions API + /api/exception_lists/items: + delete: + operationId: DeleteExceptionListItem + parameters: + - description: Either `id` or `item_id` must be specified + in: query + name: id + required: false + schema: + $ref: '#/components/schemas/ExceptionListItemId' + - description: Either `id` or `item_id` must be specified + in: query + name: item_id + required: false + schema: + $ref: '#/components/schemas/ExceptionListItemHumanId' + - in: query + name: namespace_type + required: false + schema: + $ref: '#/components/schemas/ExceptionNamespaceType' + default: single + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ExceptionListItem' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Exception list item not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Deletes an exception list item + tags: + - Exceptions API + get: + operationId: GetExceptionListItem + parameters: + - description: Either `id` or `item_id` must be specified + in: query + name: id + required: false + schema: + $ref: '#/components/schemas/ExceptionListItemId' + - description: Either `id` or `item_id` must be specified + in: query + name: item_id + required: false + schema: + $ref: '#/components/schemas/ExceptionListItemHumanId' + - in: query + name: namespace_type + required: false + schema: + $ref: '#/components/schemas/ExceptionNamespaceType' + default: single + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ExceptionListItem' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Exception list item not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Gets an exception list item + tags: + - Exceptions API + post: + operationId: CreateExceptionListItem + requestBody: + content: + application/json: + schema: + type: object + properties: + comments: + $ref: '#/components/schemas/CreateExceptionListItemCommentArray' + default: [] + description: + $ref: '#/components/schemas/ExceptionListItemDescription' + entries: + $ref: '#/components/schemas/ExceptionListItemEntryArray' + expire_time: + format: date-time + type: string + item_id: + $ref: '#/components/schemas/ExceptionListItemHumanId' + list_id: + $ref: '#/components/schemas/ExceptionListHumanId' + meta: + $ref: '#/components/schemas/ExceptionListItemMeta' + name: + $ref: '#/components/schemas/ExceptionListItemName' + namespace_type: + $ref: '#/components/schemas/ExceptionNamespaceType' + default: single + os_types: + $ref: '#/components/schemas/ExceptionListItemOsTypeArray' + default: [] + tags: + $ref: '#/components/schemas/ExceptionListItemTags' + default: [] + type: + $ref: '#/components/schemas/ExceptionListItemType' + required: + - list_id + - type + - name + - description + - entries + description: Exception list item's properties + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ExceptionListItem' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '409': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Exception list item already exists response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Creates an exception list item + tags: + - Exceptions API + put: + operationId: UpdateExceptionListItem + requestBody: + content: + application/json: + schema: + type: object + properties: + _version: + type: string + comments: + $ref: '#/components/schemas/UpdateExceptionListItemCommentArray' + default: [] + description: + $ref: '#/components/schemas/ExceptionListItemDescription' + entries: + $ref: '#/components/schemas/ExceptionListItemEntryArray' + expire_time: + format: date-time + type: string + id: + $ref: '#/components/schemas/ExceptionListItemId' + description: Either `id` or `item_id` must be specified + item_id: + $ref: '#/components/schemas/ExceptionListItemHumanId' + description: Either `id` or `item_id` must be specified + list_id: + $ref: '#/components/schemas/ExceptionListHumanId' + meta: + $ref: '#/components/schemas/ExceptionListItemMeta' + name: + $ref: '#/components/schemas/ExceptionListItemName' + namespace_type: + $ref: '#/components/schemas/ExceptionNamespaceType' + default: single + os_types: + $ref: '#/components/schemas/ExceptionListItemOsTypeArray' + default: [] + tags: + $ref: '#/components/schemas/ExceptionListItemTags' + type: + $ref: '#/components/schemas/ExceptionListItemType' + required: + - type + - name + - description + - entries + description: Exception list item's properties + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ExceptionListItem' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Exception list item not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Updates an exception list item + tags: + - Exceptions API + /api/exception_lists/items/_find: + get: + operationId: FindExceptionListItems + parameters: + - description: List's id + in: query + name: list_id + required: true + schema: + items: + $ref: '#/components/schemas/ExceptionListHumanId' + type: array + - description: > + Filters the returned results according to the value of the specified + field, + + using the `:` syntax. + in: query + name: filter + required: false + schema: + default: [] + items: + $ref: '#/components/schemas/FindExceptionListItemsFilter' + type: array + - description: > + Determines whether the returned containers are Kibana associated + with a Kibana space + + or available in all spaces (`agnostic` or `single`) + in: query + name: namespace_type + required: false + schema: + default: + - single + items: + $ref: '#/components/schemas/ExceptionNamespaceType' + type: array + - in: query + name: search + required: false + schema: + type: string + - description: The page number to return + in: query + name: page + required: false + schema: + minimum: 0 + type: integer + - description: The number of exception list items to return per page + in: query + name: per_page + required: false + schema: + minimum: 0 + type: integer + - description: Determines which field is used to sort the results + in: query + name: sort_field + required: false + schema: + $ref: '#/components/schemas/NonEmptyString' + - description: 'Determines the sort order, which can be `desc` or `asc`' + in: query + name: sort_order + required: false + schema: + enum: + - desc + - asc + type: string + responses: + '200': + content: + application/json: + schema: + type: object + properties: + data: + items: + $ref: '#/components/schemas/ExceptionListItem' + type: array + page: + minimum: 1 + type: integer + per_page: + minimum: 1 + type: integer + pit: + type: string + total: + minimum: 0 + type: integer + required: + - data + - page + - per_page + - total + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Exception list not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Finds exception list items + tags: + - Exceptions API + /api/exception_lists/summary: + get: + operationId: GetExceptionListSummary + parameters: + - description: Exception list's identifier generated upon creation + in: query + name: id + required: false + schema: + $ref: '#/components/schemas/ExceptionListId' + - description: Exception list's human readable identifier + in: query + name: list_id + required: false + schema: + $ref: '#/components/schemas/ExceptionListHumanId' + - in: query + name: namespace_type + required: false + schema: + $ref: '#/components/schemas/ExceptionNamespaceType' + default: single + - description: Search filter clause + in: query + name: filter + required: false + schema: + type: string + responses: + '200': + content: + application/json: + schema: + type: object + properties: + linux: + minimum: 0 + type: integer + macos: + minimum: 0 + type: integer + total: + minimum: 0 + type: integer + windows: + minimum: 0 + type: integer + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Exception list not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Retrieves an exception list summary + tags: + - Exceptions API + /api/exceptions/shared: + post: + operationId: CreateSharedExceptionList + requestBody: + content: + application/json: + schema: + type: object + properties: + description: + $ref: '#/components/schemas/ExceptionListDescription' + name: + $ref: '#/components/schemas/ExceptionListName' + required: + - name + - description + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ExceptionList' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '409': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Exception list already exists response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Creates a shared exception list + tags: + - Exceptions API +components: + schemas: + CreateExceptionListItemComment: + type: object + properties: + comment: + $ref: '#/components/schemas/NonEmptyString' + required: + - comment + CreateExceptionListItemCommentArray: + items: + $ref: '#/components/schemas/CreateExceptionListItemComment' + type: array + CreateRuleExceptionListItemComment: + type: object + properties: + comment: + $ref: '#/components/schemas/NonEmptyString' + required: + - comment + CreateRuleExceptionListItemCommentArray: + items: + $ref: '#/components/schemas/CreateRuleExceptionListItemComment' + type: array + CreateRuleExceptionListItemProps: + type: object + properties: + comments: + $ref: '#/components/schemas/CreateRuleExceptionListItemCommentArray' + default: [] + description: + $ref: '#/components/schemas/ExceptionListItemDescription' + entries: + $ref: '#/components/schemas/ExceptionListItemEntryArray' + expire_time: + format: date-time + type: string + item_id: + $ref: '#/components/schemas/ExceptionListItemHumanId' + meta: + $ref: '#/components/schemas/ExceptionListItemMeta' + name: + $ref: '#/components/schemas/ExceptionListItemName' + namespace_type: + $ref: '#/components/schemas/ExceptionNamespaceType' + default: single + os_types: + $ref: '#/components/schemas/ExceptionListItemOsTypeArray' + default: [] + tags: + $ref: '#/components/schemas/ExceptionListItemTags' + default: [] + type: + $ref: '#/components/schemas/ExceptionListItemType' + required: + - type + - name + - description + - entries + ExceptionList: + type: object + properties: + _version: + type: string + created_at: + format: date-time + type: string + created_by: + type: string + description: + $ref: '#/components/schemas/ExceptionListDescription' + id: + $ref: '#/components/schemas/ExceptionListId' + immutable: + type: boolean + list_id: + $ref: '#/components/schemas/ExceptionListHumanId' + meta: + $ref: '#/components/schemas/ExceptionListMeta' + name: + $ref: '#/components/schemas/ExceptionListName' + namespace_type: + $ref: '#/components/schemas/ExceptionNamespaceType' + os_types: + $ref: '#/components/schemas/ExceptionListOsTypeArray' + tags: + $ref: '#/components/schemas/ExceptionListTags' + tie_breaker_id: + type: string + type: + $ref: '#/components/schemas/ExceptionListType' + updated_at: + format: date-time + type: string + updated_by: + type: string + version: + $ref: '#/components/schemas/ExceptionListVersion' + required: + - id + - list_id + - type + - name + - description + - immutable + - namespace_type + - version + - tie_breaker_id + - created_at + - created_by + - updated_at + - updated_by + ExceptionListDescription: + type: string + ExceptionListHumanId: + $ref: '#/components/schemas/NonEmptyString' + description: 'Human readable string identifier, e.g. `trusted-linux-processes`' + ExceptionListId: + $ref: '#/components/schemas/NonEmptyString' + ExceptionListItem: + type: object + properties: + _version: + type: string + comments: + $ref: '#/components/schemas/ExceptionListItemCommentArray' + created_at: + format: date-time + type: string + created_by: + type: string + description: + $ref: '#/components/schemas/ExceptionListItemDescription' + entries: + $ref: '#/components/schemas/ExceptionListItemEntryArray' + expire_time: + format: date-time + type: string + id: + $ref: '#/components/schemas/ExceptionListItemId' + item_id: + $ref: '#/components/schemas/ExceptionListItemHumanId' + list_id: + $ref: '#/components/schemas/ExceptionListHumanId' + meta: + $ref: '#/components/schemas/ExceptionListItemMeta' + name: + $ref: '#/components/schemas/ExceptionListItemName' + namespace_type: + $ref: '#/components/schemas/ExceptionNamespaceType' + os_types: + $ref: '#/components/schemas/ExceptionListItemOsTypeArray' + tags: + $ref: '#/components/schemas/ExceptionListItemTags' + tie_breaker_id: + type: string + type: + $ref: '#/components/schemas/ExceptionListItemType' + updated_at: + format: date-time + type: string + updated_by: + type: string + required: + - id + - item_id + - list_id + - type + - name + - description + - entries + - namespace_type + - comments + - tie_breaker_id + - created_at + - created_by + - updated_at + - updated_by + ExceptionListItemComment: + type: object + properties: + comment: + $ref: '#/components/schemas/NonEmptyString' + created_at: + format: date-time + type: string + created_by: + $ref: '#/components/schemas/NonEmptyString' + id: + $ref: '#/components/schemas/NonEmptyString' + updated_at: + format: date-time + type: string + updated_by: + $ref: '#/components/schemas/NonEmptyString' + required: + - id + - comment + - created_at + - created_by + ExceptionListItemCommentArray: + items: + $ref: '#/components/schemas/ExceptionListItemComment' + type: array + ExceptionListItemDescription: + type: string + ExceptionListItemEntry: + anyOf: + - $ref: '#/components/schemas/ExceptionListItemEntryMatch' + - $ref: '#/components/schemas/ExceptionListItemEntryMatchAny' + - $ref: '#/components/schemas/ExceptionListItemEntryList' + - $ref: '#/components/schemas/ExceptionListItemEntryExists' + - $ref: '#/components/schemas/ExceptionListItemEntryNested' + - $ref: '#/components/schemas/ExceptionListItemEntryMatchWildcard' + discriminator: + propertyName: type + ExceptionListItemEntryArray: + items: + $ref: '#/components/schemas/ExceptionListItemEntry' + type: array + ExceptionListItemEntryExists: + type: object + properties: + field: + $ref: '#/components/schemas/NonEmptyString' + operator: + $ref: '#/components/schemas/ExceptionListItemEntryOperator' + type: + enum: + - exists + type: string + required: + - type + - field + - operator + ExceptionListItemEntryList: + type: object + properties: + field: + $ref: '#/components/schemas/NonEmptyString' + list: + type: object + properties: + id: + $ref: '#/components/schemas/ListId' + type: + $ref: '#/components/schemas/ListType' + required: + - id + - type + operator: + $ref: '#/components/schemas/ExceptionListItemEntryOperator' + type: + enum: + - list + type: string + required: + - type + - field + - list + - operator + ExceptionListItemEntryMatch: + type: object + properties: + field: + $ref: '#/components/schemas/NonEmptyString' + operator: + $ref: '#/components/schemas/ExceptionListItemEntryOperator' + type: + enum: + - match + type: string + value: + $ref: '#/components/schemas/NonEmptyString' + required: + - type + - field + - value + - operator + ExceptionListItemEntryMatchAny: + type: object + properties: + field: + $ref: '#/components/schemas/NonEmptyString' + operator: + $ref: '#/components/schemas/ExceptionListItemEntryOperator' + type: + enum: + - match_any + type: string + value: + items: + $ref: '#/components/schemas/NonEmptyString' + minItems: 1 + type: array + required: + - type + - field + - value + - operator + ExceptionListItemEntryMatchWildcard: + type: object + properties: + field: + $ref: '#/components/schemas/NonEmptyString' + operator: + $ref: '#/components/schemas/ExceptionListItemEntryOperator' + type: + enum: + - wildcard + type: string + value: + $ref: '#/components/schemas/NonEmptyString' + required: + - type + - field + - value + - operator + ExceptionListItemEntryNested: + type: object + properties: + entries: + items: + $ref: '#/components/schemas/ExceptionListItemEntryNestedEntryItem' + minItems: 1 + type: array + field: + $ref: '#/components/schemas/NonEmptyString' + type: + enum: + - nested + type: string + required: + - type + - field + - entries + ExceptionListItemEntryNestedEntryItem: + oneOf: + - $ref: '#/components/schemas/ExceptionListItemEntryMatch' + - $ref: '#/components/schemas/ExceptionListItemEntryMatchAny' + - $ref: '#/components/schemas/ExceptionListItemEntryExists' + ExceptionListItemEntryOperator: + enum: + - excluded + - included + type: string + ExceptionListItemHumanId: + $ref: '#/components/schemas/NonEmptyString' + ExceptionListItemId: + $ref: '#/components/schemas/NonEmptyString' + ExceptionListItemMeta: + additionalProperties: true + type: object + ExceptionListItemName: + $ref: '#/components/schemas/NonEmptyString' + ExceptionListItemOsTypeArray: + items: + $ref: '#/components/schemas/ExceptionListOsType' + type: array + ExceptionListItemTags: + items: + $ref: '#/components/schemas/NonEmptyString' + type: array + ExceptionListItemType: + enum: + - simple + type: string + ExceptionListMeta: + additionalProperties: true + type: object + ExceptionListName: + type: string + ExceptionListOsType: + enum: + - linux + - macos + - windows + type: string + ExceptionListOsTypeArray: + items: + $ref: '#/components/schemas/ExceptionListOsType' + type: array + ExceptionListsImportBulkError: + type: object + properties: + error: + type: object + properties: + message: + type: string + status_code: + type: integer + required: + - status_code + - message + id: + $ref: '#/components/schemas/ExceptionListId' + item_id: + $ref: '#/components/schemas/ExceptionListItemHumanId' + list_id: + $ref: '#/components/schemas/ExceptionListHumanId' + required: + - error + ExceptionListsImportBulkErrorArray: + items: + $ref: '#/components/schemas/ExceptionListsImportBulkError' + type: array + ExceptionListTags: + items: + type: string + type: array + ExceptionListType: + enum: + - detection + - rule_default + - endpoint + - endpoint_trusted_apps + - endpoint_events + - endpoint_host_isolation_exceptions + - endpoint_blocklists + type: string + ExceptionListVersion: + minimum: 1 + type: integer + ExceptionNamespaceType: + description: > + Determines whether the exception container is available in all Kibana + spaces or just the space + + in which it is created, where: + + + - `single`: Only available in the Kibana space in which it is created. + + - `agnostic`: Available in all Kibana spaces. + enum: + - agnostic + - single + type: string + FindExceptionListItemsFilter: + $ref: '#/components/schemas/NonEmptyString' + FindExceptionListsFilter: + type: string + ListId: + $ref: '#/components/schemas/NonEmptyString' + ListType: + enum: + - binary + - boolean + - byte + - date + - date_nanos + - date_range + - double + - double_range + - float + - float_range + - geo_point + - geo_shape + - half_float + - integer + - integer_range + - ip + - ip_range + - keyword + - long + - long_range + - shape + - short + - text + type: string + NonEmptyString: + description: A string that is not empty and does not contain only whitespace + minLength: 1 + pattern: ^(?! *$).+$ + type: string + PlatformErrorResponse: + type: object + properties: + error: + type: string + message: + type: string + statusCode: + type: integer + required: + - statusCode + - error + - message + RuleId: + $ref: '#/components/schemas/UUID' + SiemErrorResponse: + type: object + properties: + message: + type: string + status_code: + type: integer + required: + - status_code + - message + UpdateExceptionListItemComment: + type: object + properties: + comment: + $ref: '#/components/schemas/NonEmptyString' + id: + $ref: '#/components/schemas/NonEmptyString' + required: + - comment + UpdateExceptionListItemCommentArray: + items: + $ref: '#/components/schemas/UpdateExceptionListItemComment' + type: array + UUID: + description: A universally unique identifier + format: uuid + type: string + securitySchemes: + BasicAuth: + scheme: basic + type: http +security: + - BasicAuth: [] +tags: ! '' diff --git a/packages/kbn-securitysolution-exceptions-common/package.json b/packages/kbn-securitysolution-exceptions-common/package.json index 083d081d501fa..5f8fd4720518a 100644 --- a/packages/kbn-securitysolution-exceptions-common/package.json +++ b/packages/kbn-securitysolution-exceptions-common/package.json @@ -5,6 +5,7 @@ "private": true, "version": "1.0.0", "scripts": { - "openapi:generate": "node scripts/openapi_generate" + "openapi:generate": "node scripts/openapi_generate", + "openapi:bundle": "node scripts/openapi_bundle" } } diff --git a/packages/kbn-securitysolution-exceptions-common/scripts/openapi_bundle.js b/packages/kbn-securitysolution-exceptions-common/scripts/openapi_bundle.js new file mode 100644 index 0000000000000..a3e82f172b05e --- /dev/null +++ b/packages/kbn-securitysolution-exceptions-common/scripts/openapi_bundle.js @@ -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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +require('../../../src/setup_node_env'); +const { join, resolve } = require('path'); +const { bundle } = require('@kbn/openapi-bundler'); + +const ROOT = resolve(__dirname, '..'); + +(async () => { + await bundle({ + sourceGlob: join(ROOT, 'api/**/*.schema.yaml'), + outputFilePath: join( + ROOT, + 'docs/openapi/serverless/security_solution_exceptions_api_{version}.bundled.schema.yaml' + ), + options: { + includeLabels: ['serverless'], + specInfo: { + title: 'Security Solution Exceptions API (Elastic Cloud Serverless)', + description: + "Exceptions API allows you to manage detection rule exceptions to prevent a rule from generating an alert from incoming events even when the rule's other criteria are met.", + }, + }, + }); + + await bundle({ + sourceGlob: join(ROOT, 'api/**/*.schema.yaml'), + outputFilePath: join( + ROOT, + 'docs/openapi/ess/security_solution_exceptions_api_{version}.bundled.schema.yaml' + ), + options: { + includeLabels: ['ess'], + specInfo: { + title: 'Security Solution Exceptions API (Elastic Cloud and self-hosted)', + description: + "Exceptions API allows you to manage detection rule exceptions to prevent a rule from generating an alert from incoming events even when the rule's other criteria are met.", + }, + }, + }); +})(); diff --git a/packages/kbn-securitysolution-exceptions-common/scripts/openapi_generate.js b/packages/kbn-securitysolution-exceptions-common/scripts/openapi_generate.js index 9dd381501dc2b..5fd6a9fad8876 100644 --- a/packages/kbn-securitysolution-exceptions-common/scripts/openapi_generate.js +++ b/packages/kbn-securitysolution-exceptions-common/scripts/openapi_generate.js @@ -17,14 +17,14 @@ const ROOT = resolve(__dirname, '..'); await generate({ title: 'OpenAPI Exceptions API Schemas', rootDir: ROOT, - sourceGlob: './**/*.schema.yaml', + sourceGlob: './api/**/*.schema.yaml', templateName: 'zod_operation_schema', }); await generate({ title: 'Exceptions API client for tests', rootDir: ROOT, - sourceGlob: './**/*.schema.yaml', + sourceGlob: './api/**/*.schema.yaml', templateName: 'api_client_supertest', skipLinting: true, bundle: { diff --git a/packages/kbn-securitysolution-list-utils/src/helpers/index.ts b/packages/kbn-securitysolution-list-utils/src/helpers/index.ts index 433aa62487b1d..c969ac82c8a19 100644 --- a/packages/kbn-securitysolution-list-utils/src/helpers/index.ts +++ b/packages/kbn-securitysolution-list-utils/src/helpers/index.ts @@ -1032,7 +1032,8 @@ export const getMappingConflictsInfo = (field: DataViewField): FieldConflictsInf export const hasWrongOperatorWithWildcard = ( items: ExceptionsBuilderReturnExceptionItem[] ): boolean => { - return items[0]?.entries.some((e) => { + const allEntries = items.flatMap((item) => item.entries); + return allEntries.some((e) => { if (e.type !== 'list' && 'value' in e) { return validateHasWildcardWithWrongOperator({ operator: e.type, diff --git a/packages/kbn-securitysolution-lists-common/api/export_list_item/export_list_item.schema.yaml b/packages/kbn-securitysolution-lists-common/api/export_list_item/export_list_item.schema.yaml index 26708a18a899a..69dd492e86638 100644 --- a/packages/kbn-securitysolution-lists-common/api/export_list_item/export_list_item.schema.yaml +++ b/packages/kbn-securitysolution-lists-common/api/export_list_item/export_list_item.schema.yaml @@ -5,6 +5,7 @@ info: paths: /api/lists/items/_export: post: + x-labels: [serverless, ess] operationId: ExportListItems x-codegen-enabled: true summary: Exports list items diff --git a/packages/kbn-securitysolution-lists-common/api/find_list_item/find_list_item.schema.yaml b/packages/kbn-securitysolution-lists-common/api/find_list_item/find_list_item.schema.yaml index f08b2d1c6c0cd..1e822d442a4e2 100644 --- a/packages/kbn-securitysolution-lists-common/api/find_list_item/find_list_item.schema.yaml +++ b/packages/kbn-securitysolution-lists-common/api/find_list_item/find_list_item.schema.yaml @@ -3,7 +3,7 @@ info: title: Find list items API endpoint version: '2023-10-31' paths: - /api/lists/_find: + /api/lists/items/_find: get: x-labels: [serverless, ess] operationId: FindListItems diff --git a/packages/kbn-securitysolution-lists-common/api/import_list_item/import_list_item.schema.yaml b/packages/kbn-securitysolution-lists-common/api/import_list_item/import_list_item.schema.yaml index 561d52587aad2..04a0e18d76782 100644 --- a/packages/kbn-securitysolution-lists-common/api/import_list_item/import_list_item.schema.yaml +++ b/packages/kbn-securitysolution-lists-common/api/import_list_item/import_list_item.schema.yaml @@ -5,6 +5,7 @@ info: paths: /api/lists/items/_import: post: + x-labels: [serverless, ess] operationId: ImportListItems x-codegen-enabled: true summary: Imports list items diff --git a/packages/kbn-securitysolution-lists-common/docs/openapi/ess/security_solution_lists_api_2023_10_31.bundled.schema.yaml b/packages/kbn-securitysolution-lists-common/docs/openapi/ess/security_solution_lists_api_2023_10_31.bundled.schema.yaml new file mode 100644 index 0000000000000..19a11b1ec58ea --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/docs/openapi/ess/security_solution_lists_api_2023_10_31.bundled.schema.yaml @@ -0,0 +1,1523 @@ +openapi: 3.0.3 +info: + description: 'Lists API allows you to manage lists of keywords, IPs or IP ranges items.' + title: Security Solution Lists API (Elastic Cloud and self-hosted) + version: '2023-10-31' +servers: + - url: 'http://{kibana_host}:{port}' + variables: + kibana_host: + default: localhost + port: + default: '5601' +paths: + /api/lists: + delete: + operationId: DeleteList + parameters: + - description: List's `id` value + in: query + name: id + required: true + schema: + $ref: '#/components/schemas/ListId' + - in: query + name: deleteReferences + required: false + schema: + default: false + type: boolean + - in: query + name: ignoreReferences + required: false + schema: + default: false + type: boolean + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/List' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: List not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Deletes a list + tags: + - List API + get: + operationId: GetList + parameters: + - description: List's `id` value + in: query + name: id + required: true + schema: + $ref: '#/components/schemas/ListId' + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/List' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: List not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Retrieves a list using its id field + tags: + - List API + patch: + operationId: PatchList + requestBody: + content: + application/json: + schema: + type: object + properties: + _version: + type: string + description: + $ref: '#/components/schemas/ListDescription' + id: + $ref: '#/components/schemas/ListId' + meta: + $ref: '#/components/schemas/ListMetadata' + name: + $ref: '#/components/schemas/ListName' + version: + minimum: 1 + type: integer + required: + - id + description: List's properties + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/List' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: List not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Patches a list + tags: + - List API + post: + operationId: CreateList + requestBody: + content: + application/json: + schema: + type: object + properties: + description: + $ref: '#/components/schemas/ListDescription' + deserializer: + type: string + id: + $ref: '#/components/schemas/ListId' + meta: + $ref: '#/components/schemas/ListMetadata' + name: + $ref: '#/components/schemas/ListName' + serializer: + type: string + type: + $ref: '#/components/schemas/ListType' + version: + default: 1 + minimum: 1 + type: integer + required: + - name + - description + - type + description: List's properties + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/List' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '409': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: List already exists response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Creates a list + tags: + - List API + put: + operationId: UpdateList + requestBody: + content: + application/json: + schema: + type: object + properties: + _version: + type: string + description: + $ref: '#/components/schemas/ListDescription' + id: + $ref: '#/components/schemas/ListId' + meta: + $ref: '#/components/schemas/ListMetadata' + name: + $ref: '#/components/schemas/ListName' + version: + minimum: 1 + type: integer + required: + - id + - name + - description + description: List's properties + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/List' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: List not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Updates a list + tags: + - List API + /api/lists/_find: + get: + operationId: FindLists + parameters: + - description: The page number to return + in: query + name: page + required: false + schema: + type: integer + - description: The number of lists to return per page + in: query + name: per_page + required: false + schema: + type: integer + - description: Determines which field is used to sort the results + in: query + name: sort_field + required: false + schema: + $ref: '#/components/schemas/NonEmptyString' + - description: 'Determines the sort order, which can be `desc` or `asc`' + in: query + name: sort_order + required: false + schema: + enum: + - desc + - asc + type: string + - description: > + Returns the list that come after the last list returned in the + previous call + + (use the cursor value returned in the previous call). This parameter + uses + + the `tie_breaker_id` field to ensure all lists are sorted and + returned correctly. + in: query + name: cursor + required: false + schema: + $ref: '#/components/schemas/FindListsCursor' + - description: > + Filters the returned results according to the value of the specified + field, + + using the : syntax. + in: query + name: filter + required: false + schema: + $ref: '#/components/schemas/FindListsFilter' + responses: + '200': + content: + application/json: + schema: + type: object + properties: + cursor: + $ref: '#/components/schemas/FindListsCursor' + data: + items: + $ref: '#/components/schemas/List' + type: array + page: + minimum: 0 + type: integer + per_page: + minimum: 0 + type: integer + total: + minimum: 0 + type: integer + required: + - data + - page + - per_page + - total + - cursor + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Finds lists + tags: + - List API + /api/lists/index: + delete: + operationId: DeleteListIndex + responses: + '200': + content: + application/json: + schema: + type: object + properties: + acknowledged: + type: boolean + required: + - acknowledged + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: List data stream not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Deletes list data streams + tags: + - List API + get: + operationId: GetListIndex + responses: + '200': + content: + application/json: + schema: + type: object + properties: + list_index: + type: boolean + list_item_index: + type: boolean + required: + - list_index + - list_item_index + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: List data stream(s) not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Get list data stream existence status + tags: + - List API + post: + operationId: CreateListIndex + responses: + '200': + content: + application/json: + schema: + type: object + properties: + acknowledged: + type: boolean + required: + - acknowledged + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '409': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: List data stream exists response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Creates necessary list data streams + tags: + - List API + /api/lists/items: + delete: + operationId: DeleteListItem + parameters: + - description: Required if `list_id` and `value` are not specified + in: query + name: id + required: false + schema: + $ref: '#/components/schemas/ListId' + - description: Required if `id` is not specified + in: query + name: list_id + required: false + schema: + $ref: '#/components/schemas/ListId' + - description: Required if `id` is not specified + in: query + name: value + required: false + schema: + type: string + - description: >- + Determines when changes made by the request are made visible to + search + in: query + name: refresh + required: false + schema: + default: 'false' + enum: + - 'true' + - 'false' + - wait_for + type: string + responses: + '200': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/ListItem' + - items: + $ref: '#/components/schemas/ListItem' + type: array + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: List item not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Deletes a list item + tags: + - List item API + get: + operationId: GetListItem + parameters: + - description: Required if `list_id` and `value` are not specified + in: query + name: id + required: false + schema: + $ref: '#/components/schemas/ListId' + - description: Required if `id` is not specified + in: query + name: list_id + required: false + schema: + $ref: '#/components/schemas/ListId' + - description: Required if `id` is not specified + in: query + name: value + required: false + schema: + type: string + responses: + '200': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/ListItem' + - items: + $ref: '#/components/schemas/ListItem' + type: array + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: List item not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Gets a list item + tags: + - List item API + patch: + operationId: PatchListItem + requestBody: + content: + application/json: + schema: + type: object + properties: + _version: + type: string + id: + $ref: '#/components/schemas/ListItemId' + meta: + $ref: '#/components/schemas/ListItemMetadata' + refresh: + description: >- + Determines when changes made by the request are made visible + to search + enum: + - 'true' + - 'false' + - wait_for + type: string + value: + $ref: '#/components/schemas/ListItemValue' + required: + - id + description: List item's properties + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ListItem' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: List item not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Patches a list item + tags: + - List item API + post: + operationId: CreateListItem + requestBody: + content: + application/json: + schema: + type: object + properties: + id: + $ref: '#/components/schemas/ListItemId' + list_id: + $ref: '#/components/schemas/ListId' + meta: + $ref: '#/components/schemas/ListItemMetadata' + refresh: + description: >- + Determines when changes made by the request are made visible + to search + enum: + - 'true' + - 'false' + - wait_for + type: string + value: + $ref: '#/components/schemas/ListItemValue' + required: + - list_id + - value + description: List item's properties + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ListItem' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '409': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: List item already exists response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Creates a list item + tags: + - List item API + put: + operationId: UpdateListItem + requestBody: + content: + application/json: + schema: + type: object + properties: + _version: + type: string + id: + $ref: '#/components/schemas/ListItemId' + meta: + $ref: '#/components/schemas/ListItemMetadata' + value: + $ref: '#/components/schemas/ListItemValue' + required: + - id + - value + description: List item's properties + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ListItem' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: List item not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Updates a list item + tags: + - List item API + /api/lists/items/_export: + post: + description: Exports list item values from the specified list + operationId: ExportListItems + parameters: + - description: List's id to export + in: query + name: list_id + required: true + schema: + $ref: '#/components/schemas/ListId' + responses: + '200': + content: + application/ndjson: + schema: + description: A `.txt` file containing list items from the specified list + format: binary + type: string + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: List not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Exports list items + tags: + - List items Import/Export API + /api/lists/items/_find: + get: + operationId: FindListItems + parameters: + - description: List's id + in: query + name: list_id + required: true + schema: + $ref: '#/components/schemas/ListId' + - description: The page number to return + in: query + name: page + required: false + schema: + type: integer + - description: The number of list items to return per page + in: query + name: per_page + required: false + schema: + type: integer + - description: Determines which field is used to sort the results + in: query + name: sort_field + required: false + schema: + $ref: '#/components/schemas/NonEmptyString' + - description: 'Determines the sort order, which can be `desc` or `asc`' + in: query + name: sort_order + required: false + schema: + enum: + - desc + - asc + type: string + - description: > + Returns the list that come after the last list returned in the + previous call + + (use the cursor value returned in the previous call). This parameter + uses + + the `tie_breaker_id` field to ensure all lists are sorted and + returned correctly. + in: query + name: cursor + required: false + schema: + $ref: '#/components/schemas/FindListItemsCursor' + - description: > + Filters the returned results according to the value of the specified + field, + + using the : syntax. + in: query + name: filter + required: false + schema: + $ref: '#/components/schemas/FindListItemsFilter' + responses: + '200': + content: + application/json: + schema: + type: object + properties: + cursor: + $ref: '#/components/schemas/FindListItemsCursor' + data: + items: + $ref: '#/components/schemas/ListItem' + type: array + page: + minimum: 0 + type: integer + per_page: + minimum: 0 + type: integer + total: + minimum: 0 + type: integer + required: + - data + - page + - per_page + - total + - cursor + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Finds list items + tags: + - List API + /api/lists/items/_import: + post: + description: > + Imports a list of items from a `.txt` or `.csv` file. The maximum file + size is 9 million bytes. + + + You can import items to a new or existing list. + operationId: ImportListItems + parameters: + - description: | + List's id. + + Required when importing to an existing list. + in: query + name: list_id + required: false + schema: + $ref: '#/components/schemas/ListId' + - description: > + Type of the importing list. + + + Required when importing a new list that is `list_id` is not + specified. + in: query + name: type + required: false + schema: + $ref: '#/components/schemas/ListType' + - in: query + name: serializer + required: false + schema: + type: string + - in: query + name: deserializer + required: false + schema: + type: string + - description: >- + Determines when changes made by the request are made visible to + search + in: query + name: refresh + required: false + schema: + enum: + - 'true' + - 'false' + - wait_for + type: string + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + file: + description: >- + A `.txt` or `.csv` file containing newline separated list + items + format: binary + type: string + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/List' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '409': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: List with specified list_id does not exist response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Imports list items + tags: + - List items Import/Export API + /api/lists/privileges: + get: + operationId: GetListPrivileges + responses: + '200': + content: + application/json: + schema: + type: object + properties: + is_authenticated: + type: boolean + listItems: + $ref: '#/components/schemas/ListItemPrivileges' + lists: + $ref: '#/components/schemas/ListPrivileges' + required: + - lists + - listItems + - is_authenticated + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Gets list privileges + tags: + - List API +components: + schemas: + FindListItemsCursor: + $ref: '#/components/schemas/NonEmptyString' + FindListItemsFilter: + type: string + FindListsCursor: + $ref: '#/components/schemas/NonEmptyString' + FindListsFilter: + type: string + List: + type: object + properties: + _version: + type: string + '@timestamp': + format: date-time + type: string + created_at: + format: date-time + type: string + created_by: + type: string + description: + $ref: '#/components/schemas/ListDescription' + deserializer: + type: string + id: + $ref: '#/components/schemas/ListId' + immutable: + type: boolean + meta: + $ref: '#/components/schemas/ListMetadata' + name: + $ref: '#/components/schemas/ListName' + serializer: + type: string + tie_breaker_id: + type: string + type: + $ref: '#/components/schemas/ListType' + updated_at: + format: date-time + type: string + updated_by: + type: string + version: + minimum: 1 + type: integer + required: + - id + - type + - name + - description + - immutable + - version + - tie_breaker_id + - created_at + - created_by + - updated_at + - updated_by + ListDescription: + $ref: '#/components/schemas/NonEmptyString' + ListId: + $ref: '#/components/schemas/NonEmptyString' + ListItem: + type: object + properties: + _version: + type: string + '@timestamp': + format: date-time + type: string + created_at: + format: date-time + type: string + created_by: + type: string + deserializer: + type: string + id: + $ref: '#/components/schemas/ListItemId' + list_id: + $ref: '#/components/schemas/ListId' + meta: + $ref: '#/components/schemas/ListItemMetadata' + serializer: + type: string + tie_breaker_id: + type: string + type: + $ref: '#/components/schemas/ListType' + updated_at: + format: date-time + type: string + updated_by: + type: string + value: + $ref: '#/components/schemas/ListItemValue' + required: + - id + - type + - list_id + - value + - tie_breaker_id + - created_at + - created_by + - updated_at + - updated_by + ListItemId: + $ref: '#/components/schemas/NonEmptyString' + ListItemMetadata: + additionalProperties: true + type: object + ListItemPrivileges: + type: object + properties: + application: + additionalProperties: + type: boolean + type: object + cluster: + additionalProperties: + type: boolean + type: object + has_all_requested: + type: boolean + index: + additionalProperties: + additionalProperties: + type: boolean + type: object + type: object + username: + type: string + required: + - username + - has_all_requested + - cluster + - index + - application + ListItemValue: + $ref: '#/components/schemas/NonEmptyString' + ListMetadata: + additionalProperties: true + type: object + ListName: + $ref: '#/components/schemas/NonEmptyString' + ListPrivileges: + type: object + properties: + application: + additionalProperties: + type: boolean + type: object + cluster: + additionalProperties: + type: boolean + type: object + has_all_requested: + type: boolean + index: + additionalProperties: + additionalProperties: + type: boolean + type: object + type: object + username: + type: string + required: + - username + - has_all_requested + - cluster + - index + - application + ListType: + enum: + - binary + - boolean + - byte + - date + - date_nanos + - date_range + - double + - double_range + - float + - float_range + - geo_point + - geo_shape + - half_float + - integer + - integer_range + - ip + - ip_range + - keyword + - long + - long_range + - shape + - short + - text + type: string + NonEmptyString: + description: A string that is not empty and does not contain only whitespace + minLength: 1 + pattern: ^(?! *$).+$ + type: string + PlatformErrorResponse: + type: object + properties: + error: + type: string + message: + type: string + statusCode: + type: integer + required: + - statusCode + - error + - message + SiemErrorResponse: + type: object + properties: + message: + type: string + status_code: + type: integer + required: + - status_code + - message + securitySchemes: + BasicAuth: + scheme: basic + type: http +security: + - BasicAuth: [] +tags: ! '' diff --git a/packages/kbn-securitysolution-lists-common/docs/openapi/serverless/security_solution_lists_api_2023_10_31.bundled.schema.yaml b/packages/kbn-securitysolution-lists-common/docs/openapi/serverless/security_solution_lists_api_2023_10_31.bundled.schema.yaml new file mode 100644 index 0000000000000..b59461fd800d9 --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/docs/openapi/serverless/security_solution_lists_api_2023_10_31.bundled.schema.yaml @@ -0,0 +1,1523 @@ +openapi: 3.0.3 +info: + description: 'Lists API allows you to manage lists of keywords, IPs or IP ranges items.' + title: Security Solution Lists API (Elastic Cloud Serverless) + version: '2023-10-31' +servers: + - url: 'http://{kibana_host}:{port}' + variables: + kibana_host: + default: localhost + port: + default: '5601' +paths: + /api/lists: + delete: + operationId: DeleteList + parameters: + - description: List's `id` value + in: query + name: id + required: true + schema: + $ref: '#/components/schemas/ListId' + - in: query + name: deleteReferences + required: false + schema: + default: false + type: boolean + - in: query + name: ignoreReferences + required: false + schema: + default: false + type: boolean + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/List' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: List not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Deletes a list + tags: + - List API + get: + operationId: GetList + parameters: + - description: List's `id` value + in: query + name: id + required: true + schema: + $ref: '#/components/schemas/ListId' + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/List' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: List not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Retrieves a list using its id field + tags: + - List API + patch: + operationId: PatchList + requestBody: + content: + application/json: + schema: + type: object + properties: + _version: + type: string + description: + $ref: '#/components/schemas/ListDescription' + id: + $ref: '#/components/schemas/ListId' + meta: + $ref: '#/components/schemas/ListMetadata' + name: + $ref: '#/components/schemas/ListName' + version: + minimum: 1 + type: integer + required: + - id + description: List's properties + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/List' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: List not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Patches a list + tags: + - List API + post: + operationId: CreateList + requestBody: + content: + application/json: + schema: + type: object + properties: + description: + $ref: '#/components/schemas/ListDescription' + deserializer: + type: string + id: + $ref: '#/components/schemas/ListId' + meta: + $ref: '#/components/schemas/ListMetadata' + name: + $ref: '#/components/schemas/ListName' + serializer: + type: string + type: + $ref: '#/components/schemas/ListType' + version: + default: 1 + minimum: 1 + type: integer + required: + - name + - description + - type + description: List's properties + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/List' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '409': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: List already exists response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Creates a list + tags: + - List API + put: + operationId: UpdateList + requestBody: + content: + application/json: + schema: + type: object + properties: + _version: + type: string + description: + $ref: '#/components/schemas/ListDescription' + id: + $ref: '#/components/schemas/ListId' + meta: + $ref: '#/components/schemas/ListMetadata' + name: + $ref: '#/components/schemas/ListName' + version: + minimum: 1 + type: integer + required: + - id + - name + - description + description: List's properties + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/List' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: List not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Updates a list + tags: + - List API + /api/lists/_find: + get: + operationId: FindLists + parameters: + - description: The page number to return + in: query + name: page + required: false + schema: + type: integer + - description: The number of lists to return per page + in: query + name: per_page + required: false + schema: + type: integer + - description: Determines which field is used to sort the results + in: query + name: sort_field + required: false + schema: + $ref: '#/components/schemas/NonEmptyString' + - description: 'Determines the sort order, which can be `desc` or `asc`' + in: query + name: sort_order + required: false + schema: + enum: + - desc + - asc + type: string + - description: > + Returns the list that come after the last list returned in the + previous call + + (use the cursor value returned in the previous call). This parameter + uses + + the `tie_breaker_id` field to ensure all lists are sorted and + returned correctly. + in: query + name: cursor + required: false + schema: + $ref: '#/components/schemas/FindListsCursor' + - description: > + Filters the returned results according to the value of the specified + field, + + using the : syntax. + in: query + name: filter + required: false + schema: + $ref: '#/components/schemas/FindListsFilter' + responses: + '200': + content: + application/json: + schema: + type: object + properties: + cursor: + $ref: '#/components/schemas/FindListsCursor' + data: + items: + $ref: '#/components/schemas/List' + type: array + page: + minimum: 0 + type: integer + per_page: + minimum: 0 + type: integer + total: + minimum: 0 + type: integer + required: + - data + - page + - per_page + - total + - cursor + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Finds lists + tags: + - List API + /api/lists/index: + delete: + operationId: DeleteListIndex + responses: + '200': + content: + application/json: + schema: + type: object + properties: + acknowledged: + type: boolean + required: + - acknowledged + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: List data stream not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Deletes list data streams + tags: + - List API + get: + operationId: GetListIndex + responses: + '200': + content: + application/json: + schema: + type: object + properties: + list_index: + type: boolean + list_item_index: + type: boolean + required: + - list_index + - list_item_index + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: List data stream(s) not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Get list data stream existence status + tags: + - List API + post: + operationId: CreateListIndex + responses: + '200': + content: + application/json: + schema: + type: object + properties: + acknowledged: + type: boolean + required: + - acknowledged + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '409': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: List data stream exists response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Creates necessary list data streams + tags: + - List API + /api/lists/items: + delete: + operationId: DeleteListItem + parameters: + - description: Required if `list_id` and `value` are not specified + in: query + name: id + required: false + schema: + $ref: '#/components/schemas/ListId' + - description: Required if `id` is not specified + in: query + name: list_id + required: false + schema: + $ref: '#/components/schemas/ListId' + - description: Required if `id` is not specified + in: query + name: value + required: false + schema: + type: string + - description: >- + Determines when changes made by the request are made visible to + search + in: query + name: refresh + required: false + schema: + default: 'false' + enum: + - 'true' + - 'false' + - wait_for + type: string + responses: + '200': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/ListItem' + - items: + $ref: '#/components/schemas/ListItem' + type: array + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: List item not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Deletes a list item + tags: + - List item API + get: + operationId: GetListItem + parameters: + - description: Required if `list_id` and `value` are not specified + in: query + name: id + required: false + schema: + $ref: '#/components/schemas/ListId' + - description: Required if `id` is not specified + in: query + name: list_id + required: false + schema: + $ref: '#/components/schemas/ListId' + - description: Required if `id` is not specified + in: query + name: value + required: false + schema: + type: string + responses: + '200': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/ListItem' + - items: + $ref: '#/components/schemas/ListItem' + type: array + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: List item not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Gets a list item + tags: + - List item API + patch: + operationId: PatchListItem + requestBody: + content: + application/json: + schema: + type: object + properties: + _version: + type: string + id: + $ref: '#/components/schemas/ListItemId' + meta: + $ref: '#/components/schemas/ListItemMetadata' + refresh: + description: >- + Determines when changes made by the request are made visible + to search + enum: + - 'true' + - 'false' + - wait_for + type: string + value: + $ref: '#/components/schemas/ListItemValue' + required: + - id + description: List item's properties + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ListItem' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: List item not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Patches a list item + tags: + - List item API + post: + operationId: CreateListItem + requestBody: + content: + application/json: + schema: + type: object + properties: + id: + $ref: '#/components/schemas/ListItemId' + list_id: + $ref: '#/components/schemas/ListId' + meta: + $ref: '#/components/schemas/ListItemMetadata' + refresh: + description: >- + Determines when changes made by the request are made visible + to search + enum: + - 'true' + - 'false' + - wait_for + type: string + value: + $ref: '#/components/schemas/ListItemValue' + required: + - list_id + - value + description: List item's properties + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ListItem' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '409': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: List item already exists response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Creates a list item + tags: + - List item API + put: + operationId: UpdateListItem + requestBody: + content: + application/json: + schema: + type: object + properties: + _version: + type: string + id: + $ref: '#/components/schemas/ListItemId' + meta: + $ref: '#/components/schemas/ListItemMetadata' + value: + $ref: '#/components/schemas/ListItemValue' + required: + - id + - value + description: List item's properties + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ListItem' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: List item not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Updates a list item + tags: + - List item API + /api/lists/items/_export: + post: + description: Exports list item values from the specified list + operationId: ExportListItems + parameters: + - description: List's id to export + in: query + name: list_id + required: true + schema: + $ref: '#/components/schemas/ListId' + responses: + '200': + content: + application/ndjson: + schema: + description: A `.txt` file containing list items from the specified list + format: binary + type: string + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: List not found response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Exports list items + tags: + - List items Import/Export API + /api/lists/items/_find: + get: + operationId: FindListItems + parameters: + - description: List's id + in: query + name: list_id + required: true + schema: + $ref: '#/components/schemas/ListId' + - description: The page number to return + in: query + name: page + required: false + schema: + type: integer + - description: The number of list items to return per page + in: query + name: per_page + required: false + schema: + type: integer + - description: Determines which field is used to sort the results + in: query + name: sort_field + required: false + schema: + $ref: '#/components/schemas/NonEmptyString' + - description: 'Determines the sort order, which can be `desc` or `asc`' + in: query + name: sort_order + required: false + schema: + enum: + - desc + - asc + type: string + - description: > + Returns the list that come after the last list returned in the + previous call + + (use the cursor value returned in the previous call). This parameter + uses + + the `tie_breaker_id` field to ensure all lists are sorted and + returned correctly. + in: query + name: cursor + required: false + schema: + $ref: '#/components/schemas/FindListItemsCursor' + - description: > + Filters the returned results according to the value of the specified + field, + + using the : syntax. + in: query + name: filter + required: false + schema: + $ref: '#/components/schemas/FindListItemsFilter' + responses: + '200': + content: + application/json: + schema: + type: object + properties: + cursor: + $ref: '#/components/schemas/FindListItemsCursor' + data: + items: + $ref: '#/components/schemas/ListItem' + type: array + page: + minimum: 0 + type: integer + per_page: + minimum: 0 + type: integer + total: + minimum: 0 + type: integer + required: + - data + - page + - per_page + - total + - cursor + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Finds list items + tags: + - List API + /api/lists/items/_import: + post: + description: > + Imports a list of items from a `.txt` or `.csv` file. The maximum file + size is 9 million bytes. + + + You can import items to a new or existing list. + operationId: ImportListItems + parameters: + - description: | + List's id. + + Required when importing to an existing list. + in: query + name: list_id + required: false + schema: + $ref: '#/components/schemas/ListId' + - description: > + Type of the importing list. + + + Required when importing a new list that is `list_id` is not + specified. + in: query + name: type + required: false + schema: + $ref: '#/components/schemas/ListType' + - in: query + name: serializer + required: false + schema: + type: string + - in: query + name: deserializer + required: false + schema: + type: string + - description: >- + Determines when changes made by the request are made visible to + search + in: query + name: refresh + required: false + schema: + enum: + - 'true' + - 'false' + - wait_for + type: string + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + file: + description: >- + A `.txt` or `.csv` file containing newline separated list + items + format: binary + type: string + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/List' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '409': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: List with specified list_id does not exist response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Imports list items + tags: + - List items Import/Export API + /api/lists/privileges: + get: + operationId: GetListPrivileges + responses: + '200': + content: + application/json: + schema: + type: object + properties: + is_authenticated: + type: boolean + listItems: + $ref: '#/components/schemas/ListItemPrivileges' + lists: + $ref: '#/components/schemas/ListPrivileges' + required: + - lists + - listItems + - is_authenticated + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Not enough privileges response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Gets list privileges + tags: + - List API +components: + schemas: + FindListItemsCursor: + $ref: '#/components/schemas/NonEmptyString' + FindListItemsFilter: + type: string + FindListsCursor: + $ref: '#/components/schemas/NonEmptyString' + FindListsFilter: + type: string + List: + type: object + properties: + _version: + type: string + '@timestamp': + format: date-time + type: string + created_at: + format: date-time + type: string + created_by: + type: string + description: + $ref: '#/components/schemas/ListDescription' + deserializer: + type: string + id: + $ref: '#/components/schemas/ListId' + immutable: + type: boolean + meta: + $ref: '#/components/schemas/ListMetadata' + name: + $ref: '#/components/schemas/ListName' + serializer: + type: string + tie_breaker_id: + type: string + type: + $ref: '#/components/schemas/ListType' + updated_at: + format: date-time + type: string + updated_by: + type: string + version: + minimum: 1 + type: integer + required: + - id + - type + - name + - description + - immutable + - version + - tie_breaker_id + - created_at + - created_by + - updated_at + - updated_by + ListDescription: + $ref: '#/components/schemas/NonEmptyString' + ListId: + $ref: '#/components/schemas/NonEmptyString' + ListItem: + type: object + properties: + _version: + type: string + '@timestamp': + format: date-time + type: string + created_at: + format: date-time + type: string + created_by: + type: string + deserializer: + type: string + id: + $ref: '#/components/schemas/ListItemId' + list_id: + $ref: '#/components/schemas/ListId' + meta: + $ref: '#/components/schemas/ListItemMetadata' + serializer: + type: string + tie_breaker_id: + type: string + type: + $ref: '#/components/schemas/ListType' + updated_at: + format: date-time + type: string + updated_by: + type: string + value: + $ref: '#/components/schemas/ListItemValue' + required: + - id + - type + - list_id + - value + - tie_breaker_id + - created_at + - created_by + - updated_at + - updated_by + ListItemId: + $ref: '#/components/schemas/NonEmptyString' + ListItemMetadata: + additionalProperties: true + type: object + ListItemPrivileges: + type: object + properties: + application: + additionalProperties: + type: boolean + type: object + cluster: + additionalProperties: + type: boolean + type: object + has_all_requested: + type: boolean + index: + additionalProperties: + additionalProperties: + type: boolean + type: object + type: object + username: + type: string + required: + - username + - has_all_requested + - cluster + - index + - application + ListItemValue: + $ref: '#/components/schemas/NonEmptyString' + ListMetadata: + additionalProperties: true + type: object + ListName: + $ref: '#/components/schemas/NonEmptyString' + ListPrivileges: + type: object + properties: + application: + additionalProperties: + type: boolean + type: object + cluster: + additionalProperties: + type: boolean + type: object + has_all_requested: + type: boolean + index: + additionalProperties: + additionalProperties: + type: boolean + type: object + type: object + username: + type: string + required: + - username + - has_all_requested + - cluster + - index + - application + ListType: + enum: + - binary + - boolean + - byte + - date + - date_nanos + - date_range + - double + - double_range + - float + - float_range + - geo_point + - geo_shape + - half_float + - integer + - integer_range + - ip + - ip_range + - keyword + - long + - long_range + - shape + - short + - text + type: string + NonEmptyString: + description: A string that is not empty and does not contain only whitespace + minLength: 1 + pattern: ^(?! *$).+$ + type: string + PlatformErrorResponse: + type: object + properties: + error: + type: string + message: + type: string + statusCode: + type: integer + required: + - statusCode + - error + - message + SiemErrorResponse: + type: object + properties: + message: + type: string + status_code: + type: integer + required: + - status_code + - message + securitySchemes: + BasicAuth: + scheme: basic + type: http +security: + - BasicAuth: [] +tags: ! '' diff --git a/packages/kbn-securitysolution-lists-common/package.json b/packages/kbn-securitysolution-lists-common/package.json index 298f0e47bb10f..e47531892d65d 100644 --- a/packages/kbn-securitysolution-lists-common/package.json +++ b/packages/kbn-securitysolution-lists-common/package.json @@ -5,6 +5,7 @@ "private": true, "version": "1.0.0", "scripts": { - "openapi:generate": "node scripts/openapi_generate" + "openapi:generate": "node scripts/openapi_generate", + "openapi:bundle": "node scripts/openapi_bundle" } } diff --git a/packages/kbn-securitysolution-lists-common/scripts/openapi_bundle.js b/packages/kbn-securitysolution-lists-common/scripts/openapi_bundle.js new file mode 100644 index 0000000000000..9bed9a313882f --- /dev/null +++ b/packages/kbn-securitysolution-lists-common/scripts/openapi_bundle.js @@ -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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +require('../../../src/setup_node_env'); +const { join, resolve } = require('path'); +const { bundle } = require('@kbn/openapi-bundler'); + +const ROOT = resolve(__dirname, '..'); + +(async () => { + await bundle({ + sourceGlob: join(ROOT, 'api/**/*.schema.yaml'), + outputFilePath: join( + ROOT, + 'docs/openapi/serverless/security_solution_lists_api_{version}.bundled.schema.yaml' + ), + options: { + includeLabels: ['serverless'], + specInfo: { + title: 'Security Solution Lists API (Elastic Cloud Serverless)', + description: 'Lists API allows you to manage lists of keywords, IPs or IP ranges items.', + }, + }, + }); + + await bundle({ + sourceGlob: join(ROOT, 'api/**/*.schema.yaml'), + outputFilePath: join( + ROOT, + 'docs/openapi/ess/security_solution_lists_api_{version}.bundled.schema.yaml' + ), + options: { + includeLabels: ['ess'], + specInfo: { + title: 'Security Solution Lists API (Elastic Cloud and self-hosted)', + description: 'Lists API allows you to manage lists of keywords, IPs or IP ranges items.', + }, + }, + }); +})(); diff --git a/packages/kbn-securitysolution-lists-common/scripts/openapi_generate.js b/packages/kbn-securitysolution-lists-common/scripts/openapi_generate.js index 49bd2860befd6..aba406bb16b4b 100644 --- a/packages/kbn-securitysolution-lists-common/scripts/openapi_generate.js +++ b/packages/kbn-securitysolution-lists-common/scripts/openapi_generate.js @@ -17,14 +17,14 @@ const ROOT = resolve(__dirname, '..'); await generate({ title: 'OpenAPI Lists API Schemas', rootDir: ROOT, - sourceGlob: './**/*.schema.yaml', + sourceGlob: './api/**/*.schema.yaml', templateName: 'zod_operation_schema', }); await generate({ title: 'Lists API client for tests', rootDir: ROOT, - sourceGlob: './**/*.schema.yaml', + sourceGlob: './api/**/*.schema.yaml', templateName: 'api_client_supertest', skipLinting: true, bundle: { diff --git a/packages/kbn-text-based-editor/scripts/generate_esql_docs.ts b/packages/kbn-text-based-editor/scripts/generate_esql_docs.ts index f0b1f6ceeb440..06220d58f690d 100644 --- a/packages/kbn-text-based-editor/scripts/generate_esql_docs.ts +++ b/packages/kbn-text-based-editor/scripts/generate_esql_docs.ts @@ -20,20 +20,36 @@ import { functions } from '../src/esql_documentation_sections'; function loadFunctionDocs(pathToElasticsearch: string) { // Define the directory path - const dirPath = path.join(pathToElasticsearch, '/docs/reference/esql/functions/kibana/docs'); + const definitionsPath = path.join( + pathToElasticsearch, + '/docs/reference/esql/functions/kibana/definition' + ); + const docsPath = path.join(pathToElasticsearch, '/docs/reference/esql/functions/kibana/docs'); // Read the directory - const files = fs.readdirSync(dirPath); + const docsFiles = fs.readdirSync(docsPath); + + const ESFunctionDefinitions = fs + .readdirSync(definitionsPath) + .map((file) => JSON.parse(fs.readFileSync(`${definitionsPath}/${file}`, 'utf-8'))); // Initialize an empty map const functionMap = new Map(); // Iterate over each file in the directory - for (const file of files) { + for (const file of docsFiles) { // Ensure we only process .md files if (path.extname(file) === '.md') { + if ( + !ESFunctionDefinitions.find( + (def) => def.name === path.basename(file, '.md') && def.type === 'eval' + ) + ) { + // Exclude non-scalar functions (for now) + continue; + } // Read the file content - const content = fs.readFileSync(path.join(dirPath, file), 'utf-8'); + const content = fs.readFileSync(path.join(docsPath, file), 'utf-8'); // Get the function name from the file name by removing the .md extension const functionName = path.basename(file, '.md'); diff --git a/packages/kbn-text-based-editor/src/editor_footer.tsx b/packages/kbn-text-based-editor/src/editor_footer.tsx index 27a6ffbeabbdb..ca4d30c9c5071 100644 --- a/packages/kbn-text-based-editor/src/editor_footer.tsx +++ b/packages/kbn-text-based-editor/src/editor_footer.tsx @@ -101,7 +101,7 @@ interface EditorFooterProps { }; errors?: MonacoMessage[]; warnings?: MonacoMessage[]; - detectTimestamp: boolean; + detectedTimestamp?: string; onErrorClick: (error: MonacoMessage) => void; runQuery: () => void; updateQuery: (qs: string) => void; @@ -126,7 +126,7 @@ export const EditorFooter = memo(function EditorFooter({ styles, errors, warnings, - detectTimestamp, + detectedTimestamp, onErrorClick, runQuery, updateQuery, @@ -195,7 +195,7 @@ export const EditorFooter = memo(function EditorFooter({ {/* If there is no space and no @timestamp detected hide the information */} - {(detectTimestamp || !isSpaceReduced) && !hideTimeFilterInfo && ( + {(detectedTimestamp || !isSpaceReduced) && !hideTimeFilterInfo && ( @@ -207,11 +207,12 @@ export const EditorFooter = memo(function EditorFooter({

{isSpaceReduced ? '@timestamp' - : detectTimestamp + : detectedTimestamp ? i18n.translate( 'textBasedEditor.query.textBasedLanguagesEditor.timestampDetected', { - defaultMessage: '@timestamp found', + defaultMessage: '{detectedTimestamp} found', + values: { detectedTimestamp }, } ) : i18n.translate( diff --git a/packages/kbn-text-based-editor/src/esql_documentation_sections.tsx b/packages/kbn-text-based-editor/src/esql_documentation_sections.tsx index 3205c9f63f427..6dbcbad824ddd 100644 --- a/packages/kbn-text-based-editor/src/esql_documentation_sections.tsx +++ b/packages/kbn-text-based-editor/src/esql_documentation_sections.tsx @@ -877,39 +877,6 @@ export const functions = { ROW y=12.9, x=.6 | EVAL atan2=ATAN2(y, x) \`\`\` - `, - description: - 'Text is in markdown. Do not translate function names, special characters, or field names like sum(bytes)', - ignoreTag: true, - } - )} - /> - ), - }, - // Do not edit manually... automatically generated by scripts/generate_esql_docs.ts - { - label: i18n.translate( - 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.avg', - { - defaultMessage: 'AVG', - } - ), - description: ( - - - ### AVG - The average of a numeric field. - - \`\`\` - FROM employees - | STATS AVG(height) - \`\`\` `, description: 'Text is in markdown. Do not translate function names, special characters, or field names like sum(bytes)', @@ -1454,6 +1421,39 @@ export const functions = { | KEEP last_name | EVAL ln_E = ENDS_WITH(last_name, "d") \`\`\` + `, + description: + 'Text is in markdown. Do not translate function names, special characters, or field names like sum(bytes)', + ignoreTag: true, + } + )} + /> + ), + }, + // Do not edit manually... automatically generated by scripts/generate_esql_docs.ts + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.exp', + { + defaultMessage: 'EXP', + } + ), + description: ( + + + ### EXP + Returns the value of e raised to the power of the given number. + + \`\`\` + ROW d = 5.0 + | EVAL s = EXP(d) + \`\`\` `, description: 'Text is in markdown. Do not translate function names, special characters, or field names like sum(bytes)', @@ -1833,72 +1833,6 @@ export const functions = { | EVAL message = CONCAT("'", message, "'") | EVAL color = CONCAT("'", color, "'") \`\`\` - `, - description: - 'Text is in markdown. Do not translate function names, special characters, or field names like sum(bytes)', - ignoreTag: true, - } - )} - /> - ), - }, - // Do not edit manually... automatically generated by scripts/generate_esql_docs.ts - { - label: i18n.translate( - 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.max', - { - defaultMessage: 'MAX', - } - ), - description: ( - - - ### MAX - The maximum value of a field. - - \`\`\` - FROM employees - | STATS MAX(languages) - \`\`\` - `, - description: - 'Text is in markdown. Do not translate function names, special characters, or field names like sum(bytes)', - ignoreTag: true, - } - )} - /> - ), - }, - // Do not edit manually... automatically generated by scripts/generate_esql_docs.ts - { - label: i18n.translate( - 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.min', - { - defaultMessage: 'MIN', - } - ), - description: ( - - - ### MIN - The minimum value of a field. - - \`\`\` - FROM employees - | STATS MIN(languages) - \`\`\` `, description: 'Text is in markdown. Do not translate function names, special characters, or field names like sum(bytes)', @@ -3842,39 +3776,6 @@ export const functions = { \`\`\` ROW v = TO_VERSION("1.2.3") \`\`\` - `, - description: - 'Text is in markdown. Do not translate function names, special characters, or field names like sum(bytes)', - ignoreTag: true, - } - )} - /> - ), - }, - // Do not edit manually... automatically generated by scripts/generate_esql_docs.ts - { - label: i18n.translate( - 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.top', - { - defaultMessage: 'TOP', - } - ), - description: ( - - - ### TOP - Collects the top values for a field. Includes repeated values. - - \`\`\` - FROM employees - | STATS top_salaries = TOP(salary, 3, "desc"), top_salary = MAX(salary) - \`\`\` `, description: 'Text is in markdown. Do not translate function names, special characters, or field names like sum(bytes)', diff --git a/packages/kbn-text-based-editor/src/text_based_languages_editor.test.tsx b/packages/kbn-text-based-editor/src/text_based_languages_editor.test.tsx index 3744e4acb1984..1c6ed13acfa00 100644 --- a/packages/kbn-text-based-editor/src/text_based_languages_editor.test.tsx +++ b/packages/kbn-text-based-editor/src/text_based_languages_editor.test.tsx @@ -113,11 +113,11 @@ describe('TextBasedLanguagesEditor', () => { expect(component.find('[data-test-subj="TextBasedLangEditor-date-info"]').length).toBe(0); }); - it('should render the date info with @timestamp found if detectTimestamp is true', async () => { + it('should render the date info with @timestamp found if detectedTimestamp is given', async () => { const newProps = { ...props, isCodeEditorExpanded: true, - detectTimestamp: true, + detectedTimestamp: '@timestamp', }; const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); expect( diff --git a/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx b/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx index 221e245fe936f..ac7a416df7d7b 100644 --- a/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx +++ b/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx @@ -79,7 +79,7 @@ export interface TextBasedLanguagesEditorProps { * The text based queries are relying on adhoc dataviews which * can have an @timestamp timefield or nothing */ - detectTimestamp?: boolean; + detectedTimestamp?: string; /** Array of errors */ errors?: Error[]; /** Warning string as it comes from ES */ @@ -150,7 +150,7 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ onTextLangQuerySubmit, expandCodeEditor, isCodeEditorExpanded, - detectTimestamp = false, + detectedTimestamp, errors: serverErrors, warning: serverWarning, isLoading, @@ -984,7 +984,7 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ onErrorClick={onErrorClick} runQuery={onQuerySubmit} updateQuery={onQueryUpdate} - detectTimestamp={detectTimestamp} + detectedTimestamp={detectedTimestamp} editorIsInline={editorIsInline} disableSubmitAction={disableSubmitAction} hideRunQueryText={hideRunQueryText} @@ -1083,7 +1083,7 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ onErrorClick={onErrorClick} runQuery={onQuerySubmit} updateQuery={onQueryUpdate} - detectTimestamp={detectTimestamp} + detectedTimestamp={detectedTimestamp} hideRunQueryText={hideRunQueryText} editorIsInline={editorIsInline} disableSubmitAction={disableSubmitAction} diff --git a/packages/kbn-triggers-actions-ui-types/action_group_types.ts b/packages/kbn-triggers-actions-ui-types/action_group_types.ts new file mode 100644 index 0000000000000..1a8f3bae3ecc0 --- /dev/null +++ b/packages/kbn-triggers-actions-ui-types/action_group_types.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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ActionGroup } from '@kbn/alerting-types'; + +export type OmitMessageVariablesType = 'all' | 'keepContext'; + +export interface ActionGroupWithMessageVariables extends ActionGroup { + omitMessageVariables?: OmitMessageVariablesType; + defaultActionMessage?: string; +} diff --git a/packages/kbn-triggers-actions-ui-types/index.ts b/packages/kbn-triggers-actions-ui-types/index.ts index 370ead3bd4f17..0ca2b3993817c 100644 --- a/packages/kbn-triggers-actions-ui-types/index.ts +++ b/packages/kbn-triggers-actions-ui-types/index.ts @@ -8,3 +8,4 @@ export * from './rule_types'; export * from './action_variable_types'; +export * from './action_group_types'; diff --git a/packages/kbn-unified-data-table/src/components/__snapshots__/data_table_columns.test.tsx.snap b/packages/kbn-unified-data-table/src/components/__snapshots__/data_table_columns.test.tsx.snap index 7a2a8058d10f0..b74c4c1cc90d9 100644 --- a/packages/kbn-unified-data-table/src/components/__snapshots__/data_table_columns.test.tsx.snap +++ b/packages/kbn-unified-data-table/src/components/__snapshots__/data_table_columns.test.tsx.snap @@ -320,6 +320,7 @@ Array [ "_score", ], "name": "index-pattern-with-timefield", + "setFieldCount": [MockFunction], "timeFieldName": "timestamp", "title": "index-pattern-with-timefield-title", "toMinimalSpec": [Function], @@ -564,6 +565,7 @@ Array [ "_score", ], "name": "index-pattern-with-timefield", + "setFieldCount": [MockFunction], "timeFieldName": "timestamp", "title": "index-pattern-with-timefield-title", "toMinimalSpec": [Function], @@ -820,6 +822,7 @@ Array [ "_score", ], "name": "index-pattern-with-timefield", + "setFieldCount": [MockFunction], "timeFieldName": "timestamp", "title": "index-pattern-with-timefield-title", "toMinimalSpec": [Function], @@ -1063,6 +1066,7 @@ Array [ "_score", ], "name": "index-pattern-with-timefield", + "setFieldCount": [MockFunction], "timeFieldName": "timestamp", "title": "index-pattern-with-timefield-title", "toMinimalSpec": [Function], @@ -1351,6 +1355,7 @@ Array [ "_score", ], "name": "index-pattern-with-timefield", + "setFieldCount": [MockFunction], "timeFieldName": "timestamp", "title": "index-pattern-with-timefield-title", "toMinimalSpec": [Function], @@ -1632,6 +1637,7 @@ Array [ "_score", ], "name": "index-pattern-with-timefield", + "setFieldCount": [MockFunction], "timeFieldName": "timestamp", "title": "index-pattern-with-timefield-title", "toMinimalSpec": [Function], @@ -1795,6 +1801,7 @@ Array [ "_score", ], "name": "index-pattern-with-timefield", + "setFieldCount": [MockFunction], "timeFieldName": "timestamp", "title": "index-pattern-with-timefield-title", "toMinimalSpec": [Function], @@ -1950,6 +1957,7 @@ Array [ "_score", ], "name": "index-pattern-with-timefield", + "setFieldCount": [MockFunction], "timeFieldName": "timestamp", "title": "index-pattern-with-timefield-title", "toMinimalSpec": [Function], @@ -2152,6 +2160,7 @@ Array [ "_score", ], "name": "index-pattern-with-timefield", + "setFieldCount": [MockFunction], "timeFieldName": "timestamp", "title": "index-pattern-with-timefield-title", "toMinimalSpec": [Function], @@ -2366,6 +2375,7 @@ Array [ "_score", ], "name": "index-pattern-with-timefield", + "setFieldCount": [MockFunction], "timeFieldName": "timestamp", "title": "index-pattern-with-timefield-title", "toMinimalSpec": [Function], @@ -2566,6 +2576,7 @@ Array [ "_score", ], "name": "index-pattern-with-timefield", + "setFieldCount": [MockFunction], "timeFieldName": "timestamp", "title": "index-pattern-with-timefield-title", "toMinimalSpec": [Function], @@ -2768,6 +2779,7 @@ Array [ "_score", ], "name": "index-pattern-with-timefield", + "setFieldCount": [MockFunction], "timeFieldName": "timestamp", "title": "index-pattern-with-timefield-title", "toMinimalSpec": [Function], @@ -3007,6 +3019,7 @@ Array [ "_score", ], "name": "index-pattern-with-timefield", + "setFieldCount": [MockFunction], "timeFieldName": "timestamp", "title": "index-pattern-with-timefield-title", "toMinimalSpec": [Function], @@ -3224,6 +3237,7 @@ Array [ "_score", ], "name": "index-pattern-with-timefield", + "setFieldCount": [MockFunction], "timeFieldName": "timestamp", "title": "index-pattern-with-timefield-title", "toMinimalSpec": [Function], diff --git a/packages/kbn-unified-data-table/src/types.ts b/packages/kbn-unified-data-table/src/types.ts index 8f5d5e9a4035d..5914fa03f8827 100644 --- a/packages/kbn-unified-data-table/src/types.ts +++ b/packages/kbn-unified-data-table/src/types.ts @@ -6,12 +6,12 @@ * Side Public License, v 1. */ -import React from 'react'; -import { EuiDataGridCellValueElementProps, type EuiDataGridColumn } from '@elastic/eui'; +import type { ReactElement } from 'react'; +import type { EuiDataGridCellValueElementProps, EuiDataGridColumn } from '@elastic/eui'; import type { DataTableRecord } from '@kbn/discover-utils/src/types'; import type { DataView } from '@kbn/data-views-plugin/common'; import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; -import { EuiDataGridControlColumn } from '@elastic/eui/src/components/datagrid/data_grid_types'; +import type { EuiDataGridControlColumn } from '@elastic/eui/src/components/datagrid/data_grid_types'; import type { DatatableColumnMeta } from '@kbn/expressions-plugin/common'; /** @@ -57,7 +57,7 @@ export type DataGridCellValueElementProps = EuiDataGridCellValueElementProps & { export type CustomCellRenderer = Record< string, - (props: DataGridCellValueElementProps) => React.ReactNode + (props: DataGridCellValueElementProps) => ReactElement >; export interface CustomGridColumnProps { diff --git a/packages/kbn-unified-data-table/src/utils/get_render_cell_value.tsx b/packages/kbn-unified-data-table/src/utils/get_render_cell_value.tsx index 35234bdb58d8f..6a10b0950946d 100644 --- a/packages/kbn-unified-data-table/src/utils/get_render_cell_value.tsx +++ b/packages/kbn-unified-data-table/src/utils/get_render_cell_value.tsx @@ -78,22 +78,24 @@ export const getRenderCellValueFn = ({ return -; } - if (!!externalCustomRenderers && !!externalCustomRenderers[columnId]) { + const CustomCellRenderer = externalCustomRenderers?.[columnId]; + + if (CustomCellRenderer) { return ( - {externalCustomRenderers[columnId]({ - rowIndex, - columnId, - isDetails, - setCellProps, - isExpandable, - isExpanded, - colIndex, - row, - dataView, - fieldFormats, - closePopover, - })} + ); } diff --git a/packages/kbn-unified-data-table/src/utils/popularize_field.test.ts b/packages/kbn-unified-data-table/src/utils/popularize_field.test.ts index 1e24f707f2e6d..a53c435397fa5 100644 --- a/packages/kbn-unified-data-table/src/utils/popularize_field.test.ts +++ b/packages/kbn-unified-data-table/src/utils/popularize_field.test.ts @@ -38,11 +38,13 @@ describe('Popularize field', () => { }); test('do not updates saved object if data view is not persisted', async () => { + const field = { count: 0 }; const dataView = { id: 'id', fields: { - getByName: () => ({ count: 0 }), + getByName: () => field, }, + setFieldCount: jest.fn(), isPersisted: () => false, } as unknown as DataView; const updateSavedObjectMock = jest.fn(); @@ -62,6 +64,9 @@ describe('Popularize field', () => { fields: { getByName: () => field, }, + setFieldCount: jest.fn().mockImplementation((fieldName, count) => { + field.count = count; + }), isPersisted: () => true, } as unknown as DataView; const fieldName = '@timestamp'; @@ -84,6 +89,9 @@ describe('Popularize field', () => { fields: { getByName: () => field, }, + setFieldCount: jest.fn().mockImplementation((fieldName, count) => { + field.count = count; + }), isPersisted: () => true, } as unknown as DataView; const fieldName = '@timestamp'; diff --git a/packages/kbn-unified-data-table/src/utils/popularize_field.ts b/packages/kbn-unified-data-table/src/utils/popularize_field.ts index 3feca3fd3d4e7..e3f3317069823 100644 --- a/packages/kbn-unified-data-table/src/utils/popularize_field.ts +++ b/packages/kbn-unified-data-table/src/utils/popularize_field.ts @@ -22,7 +22,7 @@ async function popularizeField( return; } - field.count++; + dataView.setFieldCount(fieldName, field.count + 1); if (!dataView.isPersisted()) { return; 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 43bebba6e660b..e664a447c568c 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 @@ -20,6 +20,7 @@ import { import { i18n } from '@kbn/i18n'; import { FieldDescription } from '@kbn/field-utils'; import type { DataViewField } from '@kbn/data-views-plugin/common'; +import type { FieldsMetadataPublicStart } from '@kbn/fields-metadata-plugin/public'; import type { AddFieldFilterHandler } from '../../types'; export interface FieldPopoverHeaderProps { @@ -33,6 +34,9 @@ export interface FieldPopoverHeaderProps { onAddFilter?: AddFieldFilterHandler; onEditField?: (fieldName: string) => unknown; onDeleteField?: (fieldName: string) => unknown; + services?: { + fieldsMetadata?: FieldsMetadataPublicStart; + }; } export const FieldPopoverHeader: React.FC = ({ @@ -46,6 +50,7 @@ export const FieldPopoverHeader: React.FC = ({ onAddFilter, onEditField, onDeleteField, + services, }) => { if (!field) { return null; @@ -153,12 +158,20 @@ export const FieldPopoverHeader: React.FC = ({ )} - {field.customDescription ? ( - <> - - - - ) : null} + + + ); +}; + +const FieldDescriptionWrapper: React.FC = ({ children }) => { + return ( + <> + + {children} ); }; 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 d9e02d423cd9e..0f74965c9687d 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 @@ -10,6 +10,7 @@ import React, { memo, useCallback, useMemo, useState } from 'react'; import { EuiSpacer, EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { UiCounterMetricType } from '@kbn/analytics'; +import type { FieldsMetadataPublicStart } from '@kbn/fields-metadata-plugin/public'; import { Draggable } from '@kbn/dom-drag-drop'; import type { DataView, DataViewField } from '@kbn/data-views-plugin/public'; import type { SearchMode } from '../../types'; @@ -119,6 +120,7 @@ export interface UnifiedFieldListItemProps { */ services: UnifiedFieldListItemStatsProps['services'] & { uiActions?: FieldPopoverFooterProps['uiActions']; + fieldsMetadata?: FieldsMetadataPublicStart; }; /** * Current search mode @@ -367,6 +369,7 @@ function UnifiedFieldListItemComponent({ data-test-subj={stateService.creationOptions.dataTestSubj?.fieldListItemPopoverDataTestSubj} renderHeader={() => ( "app_search_telemetry": "36234f19573ad397ac30197c45ac219921cc3106", "application_usage_daily": "20142d23fe5d05ba22b4bc46614d99883bc488f0", "application_usage_totals": "a29ab014edc20382b9ce22ede221b18cee5d93a6", + "background-task-node": "e61f0ea9923fa05b3af0aae6c6baf2f0283e14b3", "canvas-element": "cdedc2123eb8a1506b87a56b0bcce60f4ec08bc8", "canvas-workpad": "9d82aafb19586b119e5c9382f938abe28c26ca5c", "canvas-workpad-template": "c077b0087346776bb3542b51e1385d172cb24179", 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 8d0670b977091..eebeaf9673973 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 @@ -27,6 +27,7 @@ const previouslyRegisteredTypes = [ 'application_usage_totals', 'application_usage_transactional', 'background-session', + 'background-task-node', 'canvas-element', 'canvas-workpad', 'canvas-workpad-template', diff --git a/src/plugins/ai_assistant_management/selection/public/routes/components/ai_assistant_selection_page.tsx b/src/plugins/ai_assistant_management/selection/public/routes/components/ai_assistant_selection_page.tsx index 24dc00cae84f6..3b50e26d4de08 100644 --- a/src/plugins/ai_assistant_management/selection/public/routes/components/ai_assistant_selection_page.tsx +++ b/src/plugins/ai_assistant_management/selection/public/routes/components/ai_assistant_selection_page.tsx @@ -20,6 +20,7 @@ import { EuiText, EuiTitle, } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; import { useAppContext } from '../../app_context'; export function AiAssistantSelectionPage() { @@ -86,21 +87,25 @@ export function AiAssistantSelectionPage() { ) : null}

- {i18n.translate( - 'aiAssistantManagementSelection.aiAssistantSelectionPage.obsAssistant.documentationLinkDescription', - { defaultMessage: 'For more info, see our' } - )}{' '} - - {i18n.translate( - 'aiAssistantManagementSelection.aiAssistantSelectionPage.obsAssistant.documentationLinkLabel', - { defaultMessage: 'documentation' } - )} - + + {i18n.translate( + 'aiAssistantManagementSelection.aiAssistantSelectionPage.obsAssistant.documentationLinkLabel', + { defaultMessage: 'documentation' } + )} + + ), + }} + />

) : null}

- {i18n.translate( - 'aiAssistantManagementSelection.aiAssistantSelectionPage.securityAssistant.documentationLinkDescription', - { defaultMessage: 'For more info, see our' } - )}{' '} - - {i18n.translate( - 'aiAssistantManagementSelection.aiAssistantSettingsPage.securityAssistant.documentationLinkLabel', - { defaultMessage: 'documentation' } - )} - + + {i18n.translate( + 'aiAssistantManagementSelection.aiAssistantSettingsPage.securityAssistant.documentationLinkLabel', + { defaultMessage: 'documentation' } + )} + + ), + }} + />

({ diff --git a/src/plugins/data/common/search/expressions/esql.ts b/src/plugins/data/common/search/expressions/esql.ts index 6073bc5297991..c36024bdb1b5d 100644 --- a/src/plugins/data/common/search/expressions/esql.ts +++ b/src/plugins/data/common/search/expressions/esql.ts @@ -12,6 +12,7 @@ import { i18n } from '@kbn/i18n'; import type { IKibanaSearchResponse, IKibanaSearchRequest } from '@kbn/search-types'; import type { Datatable, ExpressionFunctionDefinition } from '@kbn/expressions-plugin/common'; import { RequestAdapter } from '@kbn/inspector-plugin/common'; +import { getEarliestLatestParams } from '@kbn/esql-utils'; import { zipObject } from 'lodash'; import { Observable, defer, throwError } from 'rxjs'; @@ -152,6 +153,13 @@ export const getEsqlFn = ({ getStartDependencies }: EsqlFnArguments) => { const esQueryConfigs = getEsQueryConfig( uiSettings as Parameters[0] ); + + const namedParams = getEarliestLatestParams(query, input.timeRange); + + if (namedParams.length) { + params.params = namedParams; + } + const timeFilter = input.timeRange && getTime(undefined, input.timeRange, { diff --git a/src/plugins/data/tsconfig.json b/src/plugins/data/tsconfig.json index 3c8d6b1718439..cc6ced2bef611 100644 --- a/src/plugins/data/tsconfig.json +++ b/src/plugins/data/tsconfig.json @@ -55,7 +55,7 @@ "@kbn/react-kibana-mount", "@kbn/search-types", "@kbn/safer-lodash-set", - "@kbn/esql-utils", + "@kbn/esql-utils" ], "exclude": [ "target/**/*", diff --git a/src/plugins/data_view_field_editor/public/components/preview/preview_controller.tsx b/src/plugins/data_view_field_editor/public/components/preview/preview_controller.tsx index ea1a364960edd..ee510a3a0791f 100644 --- a/src/plugins/data_view_field_editor/public/components/preview/preview_controller.tsx +++ b/src/plugins/data_view_field_editor/public/components/preview/preview_controller.tsx @@ -187,7 +187,10 @@ export class PreviewController { this.dataView.setFieldCustomLabel(updatedField.name, updatedField.customLabel); this.dataView.setFieldCustomDescription(updatedField.name, updatedField.customDescription); - editedField.count = updatedField.popularity || 0; + if (updatedField.popularity !== undefined) { + this.dataView.setFieldCount(updatedField.name, updatedField.popularity || 0); + } + if (updatedField.format) { this.dataView.setFieldFormat(updatedField.name, updatedField.format!); } else { diff --git a/src/plugins/data_views/common/data_views/abstract_data_views.ts b/src/plugins/data_views/common/data_views/abstract_data_views.ts index 42d1b5feb0d61..4db556bc59eab 100644 --- a/src/plugins/data_views/common/data_views/abstract_data_views.ts +++ b/src/plugins/data_views/common/data_views/abstract_data_views.ts @@ -134,6 +134,7 @@ export abstract class AbstractDataView { constructor(config: AbstractDataViewDeps) { const { spec = {}, fieldFormats, shortDotsEnable = false, metaFields = [] } = config; + // it's importing field attributes when a data view is imported from a spec and those attributes aren't provided in the fieldAttrs const extractedFieldAttrs = spec?.fields ? Object.entries(spec.fields).reduce((acc, [key, value]) => { const attrs: FieldAttrSet = {}; @@ -149,6 +150,11 @@ export abstract class AbstractDataView { hasAttrs = true; } + if (value.customDescription) { + attrs.customDescription = value.customDescription; + hasAttrs = true; + } + if (hasAttrs) { acc[key] = attrs; } diff --git a/src/plugins/data_views/common/data_views/data_view.test.ts b/src/plugins/data_views/common/data_views/data_view.test.ts index 5b5c4ebd879b2..2aa736953f14a 100644 --- a/src/plugins/data_views/common/data_views/data_view.test.ts +++ b/src/plugins/data_views/common/data_views/data_view.test.ts @@ -247,6 +247,7 @@ describe('IndexPattern', () => { ...runtime, popularity: 5, customLabel: 'custom name', + customDescription: 'custom desc', format: { id: 'bytes', }, @@ -275,6 +276,7 @@ describe('IndexPattern', () => { ...runtimeComposite.fields.a, popularity: 3, customLabel: 'custom name a', + customDescription: 'custom desc a', format: { id: 'bytes', }, @@ -283,6 +285,7 @@ describe('IndexPattern', () => { ...runtimeComposite.fields.b, popularity: 4, customLabel: 'custom name b', + customDescription: 'custom desc b', format: { id: 'bytes', }, @@ -311,8 +314,10 @@ describe('IndexPattern', () => { id: 'bytes', }); expect(field.customLabel).toEqual('custom name'); + expect(field.customDescription).toEqual('custom desc'); expect(indexPattern.toSpec().fieldAttrs!['@tags']).toEqual({ customLabel: 'custom name', + customDescription: 'custom desc', count: 5, }); @@ -376,6 +381,20 @@ describe('IndexPattern', () => { indexPattern.removeRuntimeField(newField); }); + test('add and remove a custom description from a runtime field', () => { + const newField = 'new_field_test'; + indexPattern.addRuntimeField(newField, { + ...runtimeWithAttrs, + customDescription: 'test1', + }); + expect(indexPattern.getFieldByName(newField)?.customDescription).toEqual('test1'); + indexPattern.setFieldCustomDescription(newField, 'test2'); + expect(indexPattern.getFieldByName(newField)?.customDescription).toEqual('test2'); + indexPattern.setFieldCustomDescription(newField, undefined); + expect(indexPattern.getFieldByName(newField)?.customDescription).toBeUndefined(); + indexPattern.removeRuntimeField(newField); + }); + test('add and remove composite runtime field as new fields', () => { const fieldCount = indexPattern.fields.length; indexPattern.addRuntimeField('new_field', runtimeCompositeWithAttrs); @@ -390,10 +409,12 @@ describe('IndexPattern', () => { expect(indexPattern.toSpec().fieldAttrs!['new_field.a']).toEqual({ count: 3, customLabel: 'custom name a', + customDescription: 'custom desc a', }); expect(indexPattern.toSpec().fieldAttrs!['new_field.b']).toEqual({ count: 4, customLabel: 'custom name b', + customDescription: 'custom desc b', }); indexPattern.removeRuntimeField('new_field'); @@ -485,6 +506,66 @@ describe('IndexPattern', () => { }); }); + describe('should initialize from spec with field attributes', () => { + it('should read field attrs from fields', () => { + const dataView = create('test', { + fields: { + test1: { + name: 'test1', + type: 'keyword', + aggregatable: true, + searchable: true, + readFromDocValues: false, + customLabel: 'custom test1', + customDescription: 'custom test1 desc', + count: 5, + }, + }, + }); + expect(dataView.getFieldAttrs()).toMatchInlineSnapshot(` + Object { + "test1": Object { + "count": 5, + "customDescription": "custom test1 desc", + "customLabel": "custom test1", + }, + } + `); + }); + + it('should read field attrs from fields or fieldAttrs', () => { + const dataView = create('test', { + fields: { + test1: { + name: 'test1', + type: 'keyword', + aggregatable: true, + searchable: true, + readFromDocValues: false, + customLabel: 'custom test1', + customDescription: 'custom test1 desc', + }, + }, + fieldAttrs: { + test1: { + customLabel: 'custom test2', + customDescription: 'custom test2 desc', + count: 2, + }, + }, + }); + expect(dataView.getFieldAttrs()).toMatchInlineSnapshot(` + Object { + "test1": Object { + "count": 2, + "customDescription": "custom test2 desc", + "customLabel": "custom test2", + }, + } + `); + }); + }); + describe('toMinimalSpec', () => { test('can exclude fields', () => { expect(indexPattern.toMinimalSpec()).toMatchSnapshot(); diff --git a/src/plugins/data_views/common/data_views/data_view_lazy.test.ts b/src/plugins/data_views/common/data_views/data_view_lazy.test.ts index 4d65f2ece7aea..836ef451dafbe 100644 --- a/src/plugins/data_views/common/data_views/data_view_lazy.test.ts +++ b/src/plugins/data_views/common/data_views/data_view_lazy.test.ts @@ -311,6 +311,7 @@ describe('DataViewLazy', () => { ...runtime, popularity: 5, customLabel: 'custom name', + customDescription: 'custom desc', format: { id: 'bytes', }, @@ -339,6 +340,7 @@ describe('DataViewLazy', () => { ...runtimeComposite.fields.a, popularity: 3, customLabel: 'custom name a', + customDescription: 'custom desc a', format: { id: 'bytes', }, @@ -347,6 +349,7 @@ describe('DataViewLazy', () => { ...runtimeComposite.fields.b, popularity: 4, customLabel: 'custom name b', + customDescription: 'custom desc b', format: { id: 'bytes', }, @@ -461,6 +464,21 @@ describe('DataViewLazy', () => { dataViewLazy.removeRuntimeField(newField); }); + test('add and remove a custom description from a runtime field', async () => { + const newField = 'new_field_test'; + fieldCapsResponse = []; + dataViewLazy.addRuntimeField(newField, { + ...runtimeWithAttrs, + customDescription: 'test1', + }); + expect((await dataViewLazy.getFieldByName(newField))?.customDescription).toEqual('test1'); + dataViewLazy.setFieldCustomDescription(newField, 'test2'); + expect((await dataViewLazy.getFieldByName(newField))?.customDescription).toEqual('test2'); + dataViewLazy.setFieldCustomDescription(newField, undefined); + expect((await dataViewLazy.getFieldByName(newField))?.customDescription).toBeUndefined(); + dataViewLazy.removeRuntimeField(newField); + }); + test('add and remove composite runtime field as new fields', async () => { const fieldMap = (await dataViewLazy.getFields({ fieldName: ['*'] })).getFieldMap(); const fieldCount = Object.values(fieldMap).length; @@ -479,10 +497,12 @@ describe('DataViewLazy', () => { expect((await dataViewLazy.toSpec(toSpecGetAllFields)).fieldAttrs!['new_field.a']).toEqual({ count: 3, customLabel: 'custom name a', + customDescription: 'custom desc a', }); expect((await dataViewLazy.toSpec(toSpecGetAllFields)).fieldAttrs!['new_field.b']).toEqual({ count: 4, customLabel: 'custom name b', + customDescription: 'custom desc b', }); dataViewLazy.removeRuntimeField('new_field'); diff --git a/src/plugins/data_views/common/data_views/data_view_lazy.ts b/src/plugins/data_views/common/data_views/data_view_lazy.ts index 5bab48ff7b300..f991fbf4b44d8 100644 --- a/src/plugins/data_views/common/data_views/data_view_lazy.ts +++ b/src/plugins/data_views/common/data_views/data_view_lazy.ts @@ -157,7 +157,7 @@ export class DataViewLazy extends AbstractDataView { throw new CharacterNotAllowedInField('*', name); } - const { type, script, customLabel, format, popularity } = runtimeField; + const { type, script, customLabel, customDescription, format, popularity } = runtimeField; if (type === 'composite') { return this.addCompositeRuntimeField(name, runtimeField); @@ -170,6 +170,7 @@ export class DataViewLazy extends AbstractDataView { { type, script }, { customLabel, + customDescription, format, popularity, } @@ -215,6 +216,7 @@ export class DataViewLazy extends AbstractDataView { runtimeFieldSpec, { customLabel: subField.customLabel, + customDescription: subField.customDescription, format: subField.format, popularity: subField.popularity, } diff --git a/src/plugins/discover/common/data_types/logs/constants.ts b/src/plugins/discover/common/data_types/logs/constants.ts index 5726bf8439b8f..560692395a6a8 100644 --- a/src/plugins/discover/common/data_types/logs/constants.ts +++ b/src/plugins/discover/common/data_types/logs/constants.ts @@ -63,3 +63,5 @@ export const FILTER_OUT_FIELDS_PREFIXES_FOR_CONTENT = [ export const DEFAULT_ALLOWED_DATA_VIEWS = ['logs', 'auditbeat', 'filebeat', 'winlogbeat']; export const DEFAULT_ALLOWED_LOGS_DATA_VIEWS = ['logs', 'auditbeat', 'filebeat', 'winlogbeat']; + +export const LOG_LEVEL_FIELDS = ['log.level', 'log_level']; diff --git a/src/plugins/discover/kibana.jsonc b/src/plugins/discover/kibana.jsonc index b35d9aa8dd489..e2e836ec528ee 100644 --- a/src/plugins/discover/kibana.jsonc +++ b/src/plugins/discover/kibana.jsonc @@ -40,7 +40,8 @@ "noDataPage", "globalSearch", "observabilityAIAssistant", - "aiops" + "aiops", + "fieldsMetadata" ], "requiredBundles": ["kibanaUtils", "kibanaReact", "unifiedSearch", "savedObjects"], "extraPublicDirs": ["common"] diff --git a/src/plugins/discover/public/application/main/state_management/utils/get_esql_data_view.test.ts b/src/plugins/discover/public/application/main/state_management/utils/get_esql_data_view.test.ts index 81189661b543b..715a096429c53 100644 --- a/src/plugins/discover/public/application/main/state_management/utils/get_esql_data_view.test.ts +++ b/src/plugins/discover/public/application/main/state_management/utils/get_esql_data_view.test.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ - +import type { DataView } from '@kbn/data-views-plugin/public'; import { getEsqlDataView } from './get_esql_data_view'; import { dataViewAdHoc } from '../../../../__mocks__/data_view_complex'; import { dataViewMock } from '@kbn/discover-utils/src/__mocks__'; @@ -18,21 +18,33 @@ describe('getEsqlDataView', () => { id: 'ad-hoc-id', title: 'test', }); + + const dataViewAdHocNoAtTimestamp = { + ...dataViewAdHoc, + timeFieldName: undefined, + } as DataView; const services = discoverServiceMock; - it('returns the current dataview if is adhoc and query has not changed', async () => { + + it('returns the current dataview if it is adhoc with no named params and query index pattern is the same as the dataview index pattern', async () => { const query = { esql: 'from data-view-ad-hoc-title' }; - const dataView = await getEsqlDataView(query, dataViewAdHoc, services); - expect(dataView).toStrictEqual(dataViewAdHoc); + const dataView = await getEsqlDataView(query, dataViewAdHocNoAtTimestamp, services); + expect(dataView).toStrictEqual(dataViewAdHocNoAtTimestamp); + }); + + it('returns an adhoc dataview if it is adhoc with named params and query index pattern is the same as the dataview index pattern', async () => { + const query = { esql: 'from data-view-ad-hoc-title | where time >= ?earliest' }; + const dataView = await getEsqlDataView(query, dataViewAdHocNoAtTimestamp, services); + expect(dataView.timeFieldName).toBe('time'); }); - it('creates an adhoc dataview if the current dataview is persistent and query has not changed', async () => { + it('creates an adhoc dataview if the current dataview is persistent and query index pattern is the same as the dataview index pattern', async () => { const query = { esql: 'from the-data-view-title' }; const dataView = await getEsqlDataView(query, dataViewMock, services); expect(dataView.isPersisted()).toEqual(false); expect(dataView.timeFieldName).toBe('@timestamp'); }); - it('creates an adhoc dataview if the current dataview is ad hoc and query has changed', async () => { + it('creates an adhoc dataview if the current dataview is ad hoc and query index pattern is different from the dataview index pattern', async () => { discoverServiceMock.dataViews.create = jest.fn().mockReturnValue({ ...dataViewAdHoc, isPersisted: () => false, diff --git a/src/plugins/discover/public/application/main/state_management/utils/get_esql_data_view.ts b/src/plugins/discover/public/application/main/state_management/utils/get_esql_data_view.ts index 7f30ced5be035..81e3f2557bc76 100644 --- a/src/plugins/discover/public/application/main/state_management/utils/get_esql_data_view.ts +++ b/src/plugins/discover/public/application/main/state_management/utils/get_esql_data_view.ts @@ -6,7 +6,11 @@ * Side Public License, v 1. */ import type { AggregateQuery } from '@kbn/es-query'; -import { getESQLAdHocDataview, getIndexPatternFromESQLQuery } from '@kbn/esql-utils'; +import { + getESQLAdHocDataview, + getIndexPatternFromESQLQuery, + getTimeFieldFromESQLQuery, +} from '@kbn/esql-utils'; import { DataView } from '@kbn/data-views-plugin/common'; import { DiscoverServices } from '../../../../build_services'; @@ -16,12 +20,15 @@ export async function getEsqlDataView( services: DiscoverServices ) { const indexPatternFromQuery = getIndexPatternFromESQLQuery(query.esql); - + const newTimeField = getTimeFieldFromESQLQuery(query.esql); if ( currentDataView?.isPersisted() || - indexPatternFromQuery !== currentDataView?.getIndexPattern() + indexPatternFromQuery !== currentDataView?.getIndexPattern() || + // here the pattern hasn't changed but the time field has + (newTimeField !== currentDataView?.timeFieldName && + indexPatternFromQuery === currentDataView?.getIndexPattern()) ) { - return await getESQLAdHocDataview(indexPatternFromQuery, services.dataViews); + return await getESQLAdHocDataview(query.esql, services.dataViews); } return currentDataView; } diff --git a/src/plugins/discover/public/build_services.ts b/src/plugins/discover/public/build_services.ts index e1ccef0105d48..b4562140cff10 100644 --- a/src/plugins/discover/public/build_services.ts +++ b/src/plugins/discover/public/build_services.ts @@ -56,6 +56,7 @@ import { memoize, noop } from 'lodash'; import type { NoDataPagePluginStart } from '@kbn/no-data-page-plugin/public'; import type { AiopsPluginStart } from '@kbn/aiops-plugin/public'; import type { DataVisualizerPluginStart } from '@kbn/data-visualizer-plugin/public'; +import type { FieldsMetadataPublicStart } from '@kbn/fields-metadata-plugin/public'; import type { DiscoverStartPlugins } from './types'; import type { DiscoverContextAppLocator } from './application/context/services/locator'; import type { DiscoverSingleDocLocator } from './application/doc/locator'; @@ -128,6 +129,7 @@ export interface DiscoverServices { noDataPage?: NoDataPagePluginStart; observabilityAIAssistant?: ObservabilityAIAssistantPublicStart; profilesManager: ProfilesManager; + fieldsMetadata?: FieldsMetadataPublicStart; } export const buildServices = memoize( @@ -214,6 +216,7 @@ export const buildServices = memoize( noDataPage: plugins.noDataPage, observabilityAIAssistant: plugins.observabilityAIAssistant, profilesManager, + fieldsMetadata: plugins.fieldsMetadata, }; } ); diff --git a/src/plugins/discover/public/components/data_types/logs/log_level.tsx b/src/plugins/discover/public/components/data_types/logs/log_level.tsx index bddc6486f3c81..4bd0fefa04bb4 100644 --- a/src/plugins/discover/public/components/data_types/logs/log_level.tsx +++ b/src/plugins/discover/public/components/data_types/logs/log_level.tsx @@ -7,53 +7,31 @@ */ import React from 'react'; -import { useEuiTheme } from '@elastic/eui'; -import { LogFlyoutDoc } from '@kbn/discover-utils/src'; +import { LogFlyoutDoc, LogLevelBadge } from '@kbn/discover-utils/src'; import * as constants from '../../../../common/data_types/logs/constants'; -import { ChipWithPopover } from './popover_chip'; - -const LEVEL_DICT = { - error: 'danger', - warn: 'warning', - info: 'primary', - debug: 'accent', -} as const; +import { ChipPopover } from './popover_chip'; interface LogLevelProps { level: LogFlyoutDoc['log.level']; - dataTestSubj?: string; - renderInFlyout?: boolean; } -export function LogLevel({ level, dataTestSubj, renderInFlyout = false }: LogLevelProps) { - const { euiTheme } = useEuiTheme(); +export function LogLevel({ level }: LogLevelProps) { if (!level) return null; - const levelColor = LEVEL_DICT[level as keyof typeof LEVEL_DICT] - ? euiTheme.colors[LEVEL_DICT[level as keyof typeof LEVEL_DICT]] - : null; - - const truncatedLogLevel = level.length > 10 ? level.substring(0, 10) + '...' : level; - - if (renderInFlyout) { - return ( - - ); - } return ( - ( + + )} /> ); } diff --git a/src/plugins/discover/public/components/data_types/logs/log_level_badge_cell.test.tsx b/src/plugins/discover/public/components/data_types/logs/log_level_badge_cell.test.tsx new file mode 100644 index 0000000000000..000751463348c --- /dev/null +++ b/src/plugins/discover/public/components/data_types/logs/log_level_badge_cell.test.tsx @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { buildDataTableRecord, DataTableRecord } from '@kbn/discover-utils'; +import { dataViewMock } from '@kbn/discover-utils/src/__mocks__'; +import { fieldFormatsMock } from '@kbn/field-formats-plugin/common/mocks'; +import { render, screen } from '@testing-library/react'; +import React from 'react'; +import { getLogLevelBadgeCell } from './log_level_badge_cell'; + +const renderCell = (logLevelField: string, record: DataTableRecord) => { + const LogLevelBadgeCell = getLogLevelBadgeCell(logLevelField); + render( + {}} + closePopover={() => {}} + /> + ); +}; + +describe('getLogLevelBadgeCell', () => { + it('renders badge if log level is recognized', () => { + const record = buildDataTableRecord({ fields: { 'log.level': 'info' } }, dataViewMock); + renderCell('log.level', record); + expect(screen.getByTestId('logLevelBadgeCell-info')).toBeInTheDocument(); + }); + + it('renders unknown if log level is not recognized', () => { + const record = buildDataTableRecord({ fields: { 'log.level': 'unknown_level' } }, dataViewMock); + renderCell('log.level', record); + expect(screen.getByTestId('logLevelBadgeCell-unknown')).toBeInTheDocument(); + }); + + it('renders empty if no matching log level field is found', () => { + const record = buildDataTableRecord({ fields: { 'log.level': 'info' } }, dataViewMock); + renderCell('log_level', record); + expect(screen.getByTestId('logLevelBadgeCell-empty')).toBeInTheDocument(); + }); +}); diff --git a/src/plugins/discover/public/components/data_types/logs/log_level_badge_cell.tsx b/src/plugins/discover/public/components/data_types/logs/log_level_badge_cell.tsx new file mode 100644 index 0000000000000..8333c76bc4a09 --- /dev/null +++ b/src/plugins/discover/public/components/data_types/logs/log_level_badge_cell.tsx @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { CSSObject } from '@emotion/react'; +import { LogLevelBadge } from '@kbn/discover-utils'; +import type { DataGridCellValueElementProps } from '@kbn/unified-data-table'; +import React from 'react'; + +const dataTestSubj = 'logLevelBadgeCell'; +const badgeCss: CSSObject = { marginTop: '-4px' }; + +export const getLogLevelBadgeCell = + (logLevelField: string) => (props: DataGridCellValueElementProps) => { + const value = props.row.flattened[logLevelField]; + + if (!value) { + return -; + } + + return ( + {value}} + data-test-subj={dataTestSubj} + css={badgeCss} + /> + ); + }; diff --git a/src/plugins/discover/public/components/data_types/logs/popover_chip.tsx b/src/plugins/discover/public/components/data_types/logs/popover_chip.tsx index 8631cb563cddb..e90929d28af01 100644 --- a/src/plugins/discover/public/components/data_types/logs/popover_chip.tsx +++ b/src/plugins/discover/public/components/data_types/logs/popover_chip.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import React, { useCallback, useState } from 'react'; +import React, { ReactElement, useCallback, useState } from 'react'; import { EuiBadge, type EuiBadgeProps, @@ -18,7 +18,7 @@ import { EuiText, EuiButtonIcon, } from '@elastic/eui'; -import { css } from '@emotion/react'; +import { css, SerializedStyles } from '@emotion/react'; import { dynamic } from '@kbn/shared-ux-utility'; import { closeCellActionPopoverText, openCellActionPopoverAriaText } from './translations'; import { FilterInButton } from './filter_in_button'; @@ -41,9 +41,6 @@ interface ChipWithPopoverProps { dataTestSubj?: string; leftSideIcon?: React.ReactNode; rightSideIcon?: EuiBadgeProps['iconType']; - borderColor?: string | null; - style?: React.CSSProperties; - shouldRenderPopover?: boolean; } export function ChipWithPopover({ @@ -52,48 +49,71 @@ export function ChipWithPopover({ dataTestSubj = `dataTablePopoverChip_${property}`, leftSideIcon, rightSideIcon, - borderColor, - style, - shouldRenderPopover = true, }: ChipWithPopoverProps) { + return ( + ( + + + {leftSideIcon && {leftSideIcon}} + {text} + + + )} + /> + ); +} + +interface ChipPopoverProps { + /** + * ECS mapping for the key + */ + property: string; + /** + * Value for the mapping, which will be displayed + */ + text: string; + renderChip: (props: { + handleChipClick: () => void; + handleChipClickAriaLabel: string; + chipCss: SerializedStyles; + }) => ReactElement; +} + +export function ChipPopover({ property, text, renderChip }: ChipPopoverProps) { const xsFontSize = useEuiFontSize('xs').fontSize; const [isPopoverOpen, setIsPopoverOpen] = useState(false); const handleChipClick = useCallback(() => { - if (!shouldRenderPopover) return; setIsPopoverOpen(!isPopoverOpen); - }, [isPopoverOpen, shouldRenderPopover]); + }, [isPopoverOpen]); const closePopover = () => setIsPopoverOpen(false); - const chipContent = ( - - - {leftSideIcon && {leftSideIcon}} - {text} - - - ); - return ( () => ({ ...prev(), - rootProfile: () => 'root-profile', + rootProfile: () => <>root-profile, })), }, resolve: jest.fn(() => ({ @@ -46,7 +47,7 @@ export const createContextAwarenessMocks = ({ profile: { getCellRenderers: jest.fn((prev) => () => ({ ...prev(), - rootProfile: () => 'data-source-profile', + rootProfile: () => <>data-source-profile, })), }, resolve: jest.fn(() => ({ diff --git a/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/accessors/get_cell_renderers.tsx b/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/accessors/get_cell_renderers.tsx new file mode 100644 index 0000000000000..c9c75dfdb0cd5 --- /dev/null +++ b/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/accessors/get_cell_renderers.tsx @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { LOG_LEVEL_FIELDS } from '../../../../../common/data_types/logs/constants'; +import { getLogLevelBadgeCell } from '../../../../components/data_types/logs/log_level_badge_cell'; +import type { DataSourceProfileProvider } from '../../../profiles'; + +export const getCellRenderers: DataSourceProfileProvider['profile']['getCellRenderers'] = + (prev) => () => ({ + ...prev(), + ...LOG_LEVEL_FIELDS.reduce( + (acc, field) => ({ + ...acc, + [field]: getLogLevelBadgeCell(field), + [`${field}.keyword`]: getLogLevelBadgeCell(`${field}.keyword`), + }), + {} + ), + }); diff --git a/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/accessors/get_row_indicator_provider.ts b/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/accessors/get_row_indicator_provider.ts index 7980453181377..4edaa1311624b 100644 --- a/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/accessors/get_row_indicator_provider.ts +++ b/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/accessors/get_row_indicator_provider.ts @@ -12,10 +12,9 @@ import { getLogLevelColor, } from '@kbn/discover-utils'; import type { UnifiedDataTableProps } from '@kbn/unified-data-table'; +import { LOG_LEVEL_FIELDS } from '../../../../../common/data_types/logs/constants'; import type { DataSourceProfileProvider } from '../../../profiles'; -const LOG_LEVEL_FIELDS = ['log.level', 'log_level']; - export const getRowIndicatorProvider: DataSourceProfileProvider['profile']['getRowIndicatorProvider'] = () => diff --git a/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/accessors/index.ts b/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/accessors/index.ts index cf544aa298093..12522bbf915c6 100644 --- a/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/accessors/index.ts +++ b/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/accessors/index.ts @@ -7,3 +7,4 @@ */ export { getRowIndicatorProvider } from './get_row_indicator_provider'; +export { getCellRenderers } from './get_cell_renderers'; diff --git a/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/profile.test.ts b/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/profile.test.ts index 793af0a16e1b6..fe93ea90d0fd7 100644 --- a/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/profile.test.ts +++ b/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/profile.test.ts @@ -78,32 +78,32 @@ describe('logsDataSourceProfileProvider', () => { ).toEqual(RESOLUTION_MISMATCH); }); - describe('getRowIndicator', () => { - const dataViewWithLogLevel = createStubIndexPattern({ - spec: { - title: VALID_INDEX_PATTERN, - fields: { - 'log.level': { - name: 'log.level', - type: 'string', - esTypes: ['keyword'], - aggregatable: true, - searchable: true, - count: 0, - readFromDocValues: false, - scripted: false, - isMapped: true, - }, + const dataViewWithLogLevel = createStubIndexPattern({ + spec: { + title: VALID_INDEX_PATTERN, + fields: { + 'log.level': { + name: 'log.level', + type: 'string', + esTypes: ['keyword'], + aggregatable: true, + searchable: true, + count: 0, + readFromDocValues: false, + scripted: false, + isMapped: true, }, }, - }); + }, + }); - const dataViewWithoutLogLevel = createStubIndexPattern({ - spec: { - title: VALID_INDEX_PATTERN, - }, - }); + const dataViewWithoutLogLevel = createStubIndexPattern({ + spec: { + title: VALID_INDEX_PATTERN, + }, + }); + describe('getRowIndicator', () => { it('should return the correct color for a given log level', () => { const row = buildDataTableRecord({ fields: { 'log.level': 'info' } }); const euiTheme = { euiTheme: { colors: {} } } as unknown as EuiThemeComputed; @@ -140,4 +140,17 @@ describe('logsDataSourceProfileProvider', () => { expect(getRowIndicator).toBeUndefined(); }); }); + + describe('getCellRenderers', () => { + it('should return cell renderers for log level fields', () => { + const getCellRenderers = logsDataSourceProfileProvider.profile.getCellRenderers?.(() => ({})); + const cellRenderers = getCellRenderers?.(); + + expect(cellRenderers).toBeDefined(); + expect(cellRenderers?.['log.level']).toBeDefined(); + expect(cellRenderers?.['log.level.keyword']).toBeDefined(); + expect(cellRenderers?.log_level).toBeDefined(); + expect(cellRenderers?.['log_level.keyword']).toBeDefined(); + }); + }); }); diff --git a/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/profile.ts b/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/profile.ts index f32af6df8dc75..17f53f30f397b 100644 --- a/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/profile.ts +++ b/src/plugins/discover/public/context_awareness/profile_providers/logs_data_source_profile/profile.ts @@ -16,6 +16,7 @@ import { } from '../../profiles'; import { ProfileProviderServices } from '../profile_provider_services'; import { getRowIndicatorProvider } from './accessors'; +import { getCellRenderers } from './accessors'; export const createLogsDataSourceProfileProvider = ( services: ProfileProviderServices @@ -23,6 +24,7 @@ export const createLogsDataSourceProfileProvider = ( profileId: 'logs-data-source-profile', profile: { getRowIndicatorProvider, + getCellRenderers, }, resolve: (params) => { const indexPattern = extractIndexPatternFrom(params); diff --git a/src/plugins/discover/public/types.ts b/src/plugins/discover/public/types.ts index 54291a36a989b..e0aeb18dc4aa6 100644 --- a/src/plugins/discover/public/types.ts +++ b/src/plugins/discover/public/types.ts @@ -39,6 +39,7 @@ import type { } from '@kbn/observability-ai-assistant-plugin/public'; import type { AiopsPluginStart } from '@kbn/aiops-plugin/public'; import type { DataVisualizerPluginStart } from '@kbn/data-visualizer-plugin/public'; +import type { FieldsMetadataPublicStart } from '@kbn/fields-metadata-plugin/public'; import { DiscoverAppLocator } from '../common'; import { DiscoverCustomizationContext } from './customizations'; import { type DiscoverContainerProps } from './components/discover_container'; @@ -167,4 +168,5 @@ export interface DiscoverStartPlugins { unifiedSearch: UnifiedSearchPublicPluginStart; urlForwarding: UrlForwardingStart; usageCollection?: UsageCollectionSetup; + fieldsMetadata: FieldsMetadataPublicStart; } diff --git a/src/plugins/discover/tsconfig.json b/src/plugins/discover/tsconfig.json index 970f8753a8cdc..e82b70dbc7122 100644 --- a/src/plugins/discover/tsconfig.json +++ b/src/plugins/discover/tsconfig.json @@ -92,7 +92,8 @@ "@kbn/aiops-plugin", "@kbn/data-visualizer-plugin", "@kbn/search-types", - "@kbn/observability-ai-assistant-plugin" + "@kbn/observability-ai-assistant-plugin", + "@kbn/fields-metadata-plugin" ], "exclude": ["target/**/*"] } diff --git a/src/plugins/esql_datagrid/README.md b/src/plugins/esql_datagrid/README.md index 89848b34b5f4d..4003c533ecf68 100644 --- a/src/plugins/esql_datagrid/README.md +++ b/src/plugins/esql_datagrid/README.md @@ -24,7 +24,7 @@ Contains a Discover-like table specifically for ES|QL queries: ### How to use it ```tsx -import { getIndexPatternFromESQLQuery, getESQLAdHocDataview, formatESQLColumns } from '@kbn/esql-utils'; +import { getESQLAdHocDataview, formatESQLColumns } from '@kbn/esql-utils'; import { ESQLDataGrid } from '@kbn/esql-datagrid/public'; /** @@ -32,8 +32,7 @@ import { ESQLDataGrid } from '@kbn/esql-datagrid/public'; This will return a response with columns and values **/ -const indexPattern = getIndexPatternFromESQLQuery(query); -const adHocDataView = getESQLAdHocDataview(indexPattern, dataViewService); +const adHocDataView = getESQLAdHocDataview(query, dataViewService); const formattedColumns = formatESQLColumns(columns); { diff --git a/src/plugins/expressions/common/expression_functions/specs/ui_setting.ts b/src/plugins/expressions/common/expression_functions/specs/ui_setting.ts index ee4998dc8a1a1..36574f4aa7465 100644 --- a/src/plugins/expressions/common/expression_functions/specs/ui_setting.ts +++ b/src/plugins/expressions/common/expression_functions/specs/ui_setting.ts @@ -11,16 +11,39 @@ import { i18n } from '@kbn/i18n'; import { ExpressionFunctionDefinition } from '../..'; import { UiSetting } from '../../expression_types/specs/ui_setting'; -interface UiSettingsClient { +/** + * Note: The UiSettings client interface is different between the browser and server. + * For that reason we can't expose a common getUiSettingFn for both environments. + * To maintain the consistency with the current file structure, we expose 2 separate functions + * from this file inside the "common" folder. + */ + +interface UiSettingsClientBrowser { get(key: string, defaultValue?: T): T | Promise; } -interface UiSettingStartDependencies { - uiSettings: UiSettingsClient; +interface UiSettingStartDependenciesBrowser { + uiSettings: UiSettingsClientBrowser; } -interface UiSettingFnArguments { - getStartDependencies(getKibanaRequest: () => KibanaRequest): Promise; +interface UiSettingFnArgumentsBrowser { + getStartDependencies( + getKibanaRequest: () => KibanaRequest + ): Promise; +} + +interface UiSettingsClientServer { + get(key: string): T | Promise; +} + +interface UiSettingStartDependenciesServer { + uiSettings: UiSettingsClientServer; +} + +interface UiSettingFnArgumentsServer { + getStartDependencies( + getKibanaRequest: () => KibanaRequest + ): Promise; } export interface UiSettingArguments { @@ -35,40 +58,54 @@ export type ExpressionFunctionUiSetting = ExpressionFunctionDefinition< Promise >; -export function getUiSettingFn({ +const commonExpressionFnSettings: Omit = { + name: 'uiSetting', + help: i18n.translate('expressions.functions.uiSetting.help', { + defaultMessage: 'Returns a UI settings parameter value.', + }), + args: { + default: { + help: i18n.translate('expressions.functions.uiSetting.args.default', { + defaultMessage: 'A default value in case of the parameter is not set.', + }), + }, + parameter: { + aliases: ['_'], + help: i18n.translate('expressions.functions.uiSetting.args.parameter', { + defaultMessage: 'The parameter name.', + }), + required: true, + types: ['string'], + }, + }, +}; + +const kibanaRequestError = new Error( + i18n.translate('expressions.functions.uiSetting.error.kibanaRequest', { + defaultMessage: + 'A KibanaRequest is required to get UI settings on the server. ' + + 'Please provide a request object to the expression execution params.', + }) +); + +const getInvalidParameterError = (parameter: string) => + new Error( + i18n.translate('expressions.functions.uiSetting.error.parameter', { + defaultMessage: 'Invalid parameter "{parameter}".', + values: { parameter }, + }) + ); + +export function getUiSettingFnBrowser({ getStartDependencies, -}: UiSettingFnArguments): ExpressionFunctionUiSetting { +}: UiSettingFnArgumentsBrowser): ExpressionFunctionUiSetting { return { - name: 'uiSetting', - help: i18n.translate('expressions.functions.uiSetting.help', { - defaultMessage: 'Returns a UI settings parameter value.', - }), - args: { - default: { - help: i18n.translate('expressions.functions.uiSetting.args.default', { - defaultMessage: 'A default value in case of the parameter is not set.', - }), - }, - parameter: { - aliases: ['_'], - help: i18n.translate('expressions.functions.uiSetting.args.parameter', { - defaultMessage: 'The parameter name.', - }), - required: true, - types: ['string'], - }, - }, + ...commonExpressionFnSettings, async fn(input, { default: defaultValue, parameter }, { getKibanaRequest }) { const { uiSettings } = await getStartDependencies(() => { const request = getKibanaRequest?.(); if (!request) { - throw new Error( - i18n.translate('expressions.functions.uiSetting.error.kibanaRequest', { - defaultMessage: - 'A KibanaRequest is required to get UI settings on the server. ' + - 'Please provide a request object to the expression execution params.', - }) - ); + throw kibanaRequestError; } return request; @@ -81,12 +118,35 @@ export function getUiSettingFn({ value: await uiSettings.get(parameter, defaultValue), }; } catch { - throw new Error( - i18n.translate('expressions.functions.uiSetting.error.parameter', { - defaultMessage: 'Invalid parameter "{parameter}".', - values: { parameter }, - }) - ); + throw getInvalidParameterError(parameter); + } + }, + }; +} + +export function getUiSettingFnServer({ + getStartDependencies, +}: UiSettingFnArgumentsServer): ExpressionFunctionUiSetting { + return { + ...commonExpressionFnSettings, + async fn(input, { parameter }, { getKibanaRequest }) { + const { uiSettings } = await getStartDependencies(() => { + const request = getKibanaRequest?.(); + if (!request) { + throw kibanaRequestError; + } + + return request; + }); + + try { + return { + type: 'ui_setting', + key: parameter, + value: await uiSettings.get(parameter), + }; + } catch { + throw getInvalidParameterError(parameter); } }, }; diff --git a/src/plugins/expressions/common/index.ts b/src/plugins/expressions/common/index.ts index 110fc2f5594f9..d8a3f5f9e37ff 100644 --- a/src/plugins/expressions/common/index.ts +++ b/src/plugins/expressions/common/index.ts @@ -135,7 +135,8 @@ export { theme, cumulativeSum, overallMetric, - getUiSettingFn, + getUiSettingFnBrowser, + getUiSettingFnServer, buildResultColumns, getBucketIdentifier, ExpressionFunction, diff --git a/src/plugins/expressions/public/expression_functions/ui_setting.ts b/src/plugins/expressions/public/expression_functions/ui_setting.ts index 6b16952279c69..fb9d39b4c0384 100644 --- a/src/plugins/expressions/public/expression_functions/ui_setting.ts +++ b/src/plugins/expressions/public/expression_functions/ui_setting.ts @@ -7,10 +7,10 @@ */ import { CoreSetup } from '@kbn/core/public'; -import { getUiSettingFn as getCommonUiSettingFn } from '../../common'; +import { getUiSettingFnBrowser } from '../../common'; export function getUiSettingFn({ getStartServices }: Pick) { - return getCommonUiSettingFn({ + return getUiSettingFnBrowser({ async getStartDependencies() { const [{ uiSettings }] = await getStartServices(); diff --git a/src/plugins/expressions/server/expression_functions/ui_setting.ts b/src/plugins/expressions/server/expression_functions/ui_setting.ts index a490b003ce90b..ef037609e01d7 100644 --- a/src/plugins/expressions/server/expression_functions/ui_setting.ts +++ b/src/plugins/expressions/server/expression_functions/ui_setting.ts @@ -7,10 +7,10 @@ */ import { CoreSetup } from '@kbn/core/server'; -import { getUiSettingFn as getCommonUiSettingFn } from '../../common'; +import { getUiSettingFnServer } from '../../common'; export function getUiSettingFn({ getStartServices }: Pick) { - return getCommonUiSettingFn({ + return getUiSettingFnServer({ async getStartDependencies(getKibanaRequest) { const [{ savedObjects, uiSettings }] = await getStartServices(); const savedObjectsClient = savedObjects.getScopedClient(getKibanaRequest()); diff --git a/src/plugins/guided_onboarding/server/plugin.ts b/src/plugins/guided_onboarding/server/plugin.ts index 3a5138d20133b..04afe7abad4e4 100755 --- a/src/plugins/guided_onboarding/server/plugin.ts +++ b/src/plugins/guided_onboarding/server/plugin.ts @@ -9,7 +9,7 @@ import { PluginInitializerContext, CoreSetup, Plugin, Logger } from '@kbn/core/server'; import type { GuideId, GuideConfig } from '@kbn/guided-onboarding'; -import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { GUIDED_ONBOARDING_FEATURE } from './feature'; import { GuidedOnboardingPluginSetup, GuidedOnboardingPluginStart } from './types'; import { defineRoutes } from './routes'; diff --git a/src/plugins/navigation/common/constants.ts b/src/plugins/navigation/common/constants.ts index 71e1bc34c12a0..f44ed035fe8f4 100644 --- a/src/plugins/navigation/common/constants.ts +++ b/src/plugins/navigation/common/constants.ts @@ -7,3 +7,12 @@ */ export const SOLUTION_NAV_FEATURE_FLAG_NAME = 'solutionNavEnabled'; + +export const DEFAULT_ROUTE_UI_SETTING_ID = 'defaultRoute'; + +export const DEFAULT_ROUTES = { + classic: '/app/home', + es: '/app/enterprise_search/overview', + oblt: '/app/observabilityOnboarding', + security: '/app/security/get_started', +}; diff --git a/src/plugins/navigation/server/index.ts b/src/plugins/navigation/server/index.ts index 1b4c36048209e..e03478d5ad12a 100644 --- a/src/plugins/navigation/server/index.ts +++ b/src/plugins/navigation/server/index.ts @@ -5,9 +5,10 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ +import type { PluginInitializerContext } from '@kbn/core/server'; import { NavigationServerPlugin } from './plugin'; -export async function plugin() { - return new NavigationServerPlugin(); +export async function plugin(initContext: PluginInitializerContext) { + return new NavigationServerPlugin(initContext); } diff --git a/src/plugins/navigation/server/plugin.ts b/src/plugins/navigation/server/plugin.ts index fda3de0c8cc22..f4a071d6aab7a 100644 --- a/src/plugins/navigation/server/plugin.ts +++ b/src/plugins/navigation/server/plugin.ts @@ -5,7 +5,13 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import type { CoreSetup, CoreStart, Plugin } from '@kbn/core/server'; +import type { + CoreSetup, + CoreStart, + Plugin, + PluginInitializerContext, + Logger, +} from '@kbn/core/server'; import type { NavigationServerSetup, @@ -13,6 +19,7 @@ import type { NavigationServerStart, NavigationServerStartDependencies, } from './types'; +import { getUiSettings } from './ui_settings'; export class NavigationServerPlugin implements @@ -23,12 +30,18 @@ export class NavigationServerPlugin NavigationServerStartDependencies > { - constructor() {} + private readonly logger: Logger; + + constructor(initializerContext: PluginInitializerContext) { + this.logger = initializerContext.logger.get(); + } setup( core: CoreSetup, plugins: NavigationServerSetupDependencies ) { + core.uiSettings.register(getUiSettings(core, this.logger)); + return {}; } diff --git a/src/plugins/navigation/server/types.ts b/src/plugins/navigation/server/types.ts index e6fadbc6ad932..80980b245d815 100644 --- a/src/plugins/navigation/server/types.ts +++ b/src/plugins/navigation/server/types.ts @@ -7,6 +7,7 @@ */ import type { CloudExperimentsPluginStart } from '@kbn/cloud-experiments-plugin/common'; import type { CloudSetup, CloudStart } from '@kbn/cloud-plugin/server'; +import type { SpacesPluginSetup, SpacesPluginStart } from '@kbn/spaces-plugin/server'; // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface NavigationServerSetup {} @@ -16,9 +17,11 @@ export interface NavigationServerStart {} export interface NavigationServerSetupDependencies { cloud?: CloudSetup; + spaces?: SpacesPluginSetup; } export interface NavigationServerStartDependencies { cloudExperiments?: CloudExperimentsPluginStart; cloud?: CloudStart; + spaces?: SpacesPluginStart; } diff --git a/src/plugins/navigation/server/ui_settings.test.ts b/src/plugins/navigation/server/ui_settings.test.ts new file mode 100644 index 0000000000000..1d8431b359109 --- /dev/null +++ b/src/plugins/navigation/server/ui_settings.test.ts @@ -0,0 +1,72 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { coreMock, loggingSystemMock } from '@kbn/core/server/mocks'; +import type { UiSettingsParams } from '@kbn/core-ui-settings-common'; +import { spacesMock } from '@kbn/spaces-plugin/server/mocks'; +import type { Space } from '@kbn/spaces-plugin/common'; + +import { getUiSettings } from './ui_settings'; +import { DEFAULT_ROUTES } from '../common/constants'; + +describe('ui settings', () => { + const core = coreMock.createSetup(); + const logger = loggingSystemMock.createLogger(); + + const getValidationFn = (setting: UiSettingsParams) => (value: any) => + setting.schema.validate(value); + + describe('defaultRoute', () => { + it('should only accept relative urls', () => { + const uiSettings = getUiSettings(core, logger); + const validate = getValidationFn(uiSettings.defaultRoute); + + expect(() => validate('/some-url')).not.toThrow(); + expect(() => validate('http://some-url')).toThrowErrorMatchingInlineSnapshot( + `"Must be a relative URL."` + ); + expect(() => validate(125)).toThrowErrorMatchingInlineSnapshot( + `"expected value of type [string] but got [number]"` + ); + }); + + describe('getValue()', () => { + it('should return classic when neither "space" nor "request" is provided', async () => { + const { defaultRoute } = getUiSettings(core, logger); + await expect(defaultRoute.getValue!()).resolves.toBe(DEFAULT_ROUTES.classic); + }); + + it('should return the route based on the active space', async () => { + const spaces = spacesMock.createStart(); + + for (const solution of ['classic', 'es', 'oblt', 'security'] as const) { + const mockSpace: Pick = { solution }; + spaces.spacesService.getActiveSpace.mockResolvedValue(mockSpace as Space); + core.getStartServices.mockResolvedValue([{} as any, { spaces }, {} as any]); + const { defaultRoute } = getUiSettings(core, logger); + + await expect(defaultRoute.getValue!({ request: {} as any })).resolves.toBe( + DEFAULT_ROUTES[solution] + ); + } + }); + + it('should handle error thrown', async () => { + const spaces = spacesMock.createStart(); + + spaces.spacesService.getActiveSpace.mockRejectedValue(new Error('something went wrong')); + core.getStartServices.mockResolvedValue([{} as any, { spaces }, {} as any]); + const { defaultRoute } = getUiSettings(core, logger); + + await expect(defaultRoute.getValue!({ request: {} as any })).resolves.toBe( + DEFAULT_ROUTES.classic + ); + }); + }); + }); +}); diff --git a/src/plugins/navigation/server/ui_settings.ts b/src/plugins/navigation/server/ui_settings.ts new file mode 100644 index 0000000000000..bcf128f2d348a --- /dev/null +++ b/src/plugins/navigation/server/ui_settings.ts @@ -0,0 +1,66 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import type { CoreSetup, KibanaRequest, Logger } from '@kbn/core/server'; +import { schema } from '@kbn/config-schema'; +import { UiSettingsParams } from '@kbn/core/types'; +import { i18n } from '@kbn/i18n'; +import { isRelativeUrl } from '@kbn/std'; + +import { DEFAULT_ROUTE_UI_SETTING_ID, DEFAULT_ROUTES } from '../common/constants'; +import { NavigationServerStartDependencies } from './types'; + +/** + * uiSettings definitions for Navigation + */ +export const getUiSettings = ( + core: CoreSetup, + logger: Logger +): Record => { + return { + [DEFAULT_ROUTE_UI_SETTING_ID]: { + name: i18n.translate('navigation.ui_settings.params.defaultRoute.defaultRouteTitle', { + defaultMessage: 'Default route', + }), + getValue: async ({ request }: { request?: KibanaRequest } = {}) => { + const [_, { spaces }] = await core.getStartServices(); + + if (!spaces || !request) { + return DEFAULT_ROUTES.classic; + } + + try { + const activeSpace = await spaces.spacesService.getActiveSpace(request); + + const solution = activeSpace?.solution ?? 'classic'; + return DEFAULT_ROUTES[solution] ?? DEFAULT_ROUTES.classic; + } catch (e) { + logger.error(`Failed to retrieve active space: ${e.message}`); + return DEFAULT_ROUTES.classic; + } + }, + schema: schema.string({ + validate(value) { + if (!value.startsWith('/') || !isRelativeUrl(value)) { + return i18n.translate( + 'navigation.uiSettings.defaultRoute.defaultRouteIsRelativeValidationMessage', + { + defaultMessage: 'Must be a relative URL.', + } + ); + } + }, + }), + description: i18n.translate('navigation.uiSettings.defaultRoute.defaultRouteText', { + defaultMessage: + 'This setting specifies the default route when opening Kibana. ' + + 'You can use this setting to modify the landing page when opening Kibana. ' + + 'The route must be a relative URL.', + }), + }, + }; +}; diff --git a/src/plugins/navigation/tsconfig.json b/src/plugins/navigation/tsconfig.json index 53faee865c065..03a88e87ad806 100644 --- a/src/plugins/navigation/tsconfig.json +++ b/src/plugins/navigation/tsconfig.json @@ -24,6 +24,10 @@ "@kbn/config", "@kbn/cloud-experiments-plugin", "@kbn/spaces-plugin", + "@kbn/core-ui-settings-common", + "@kbn/config-schema", + "@kbn/i18n", + "@kbn/std", ], "exclude": [ "target/**/*", diff --git a/src/plugins/share/public/components/share_tabs.test.tsx b/src/plugins/share/public/components/share_tabs.test.tsx new file mode 100644 index 0000000000000..380b69a084ac9 --- /dev/null +++ b/src/plugins/share/public/components/share_tabs.test.tsx @@ -0,0 +1,103 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; +import { ShareMenuTabs } from './share_tabs'; +import { ShareTabsContext } from './context'; +import { mountWithIntl } from '@kbn/test-jest-helpers'; +import { KibanaLocation, LocatorGetUrlParams, UrlService } from '../../common/url_service'; +import { + BrowserShortUrlClient, + BrowserShortUrlClientHttp, +} from '../url_service/short_urls/short_url_client'; +import { + BrowserShortUrlClientFactoryCreateParams, + BrowserShortUrlClientFactory, +} from '../url_service/short_urls/short_url_client_factory'; +import { themeServiceMock } from '@kbn/core-theme-browser-mocks'; +import { i18nServiceMock } from '@kbn/core-i18n-browser-mocks'; +import { toastsServiceMock } from '@kbn/core-notifications-browser-mocks/src/toasts_service.mock'; +const navigate = jest.fn(async () => {}); +const getUrl = jest.fn( + async (location: KibanaLocation, params: LocatorGetUrlParams): Promise => { + return `${params.absolute ? 'https://example.com' : ''}/xyz/${location.app}/${location.path}`; + } +); +const http: BrowserShortUrlClientHttp = { + basePath: { + get: () => '/xyz', + }, + fetch: jest.fn(async () => { + return {} as any; + }), +}; +const service = new UrlService({ + baseUrl: '/xyz', + version: '1.2.3', + navigate, + getUrl, + shortUrls: ({ locators }) => + new BrowserShortUrlClientFactory({ + http, + locators, + }), +}); +const mockShareContext = { + allowEmbed: true, + allowShortUrl: true, + anonymousAccess: { getCapabilities: jest.fn(), getState: jest.fn() }, + urlService: service, + isEmbedded: true, + theme: themeServiceMock.createStartContract(), + objectTypeMeta: { title: 'title' }, + objectType: 'type', + sharingData: { title: 'title', url: 'url' }, + isDirty: false, + onClose: jest.fn(), + toasts: toastsServiceMock.createStartContract(), + i18n: i18nServiceMock.createStartContract(), +}; +const CSV = 'CSV' as const; +const PNG = 'PNG' as const; +describe('Share modal tabs', () => { + it('should render export tab when there are share menu items that are not disabled', async () => { + const testItem = [ + { shareMenuItem: { name: 'test', disabled: false }, label: CSV, generateExport: jest.fn() }, + ]; + const wrapper = mountWithIntl( + + + + ); + expect(wrapper.find('[data-test-subj="export"]').exists()).toBeTruthy(); + }); + it('should not render export tab when the license is disabled', async () => { + const testItems = [ + { shareMenuItem: { name: 'test', disabled: true }, label: CSV, generateExport: jest.fn() }, + ]; + const wrapper = mountWithIntl( + + + + ); + expect(wrapper.find('[data-test-subj="export"]').exists()).toBeFalsy(); + }); + + it('should render export tab is at least one is not disabled', async () => { + const testItem = [ + { shareMenuItem: { name: 'test', disabled: false }, label: CSV, generateExport: jest.fn() }, + { shareMenuItem: { name: 'test', disabled: true }, label: PNG, generateExport: jest.fn() }, + ]; + const wrapper = mountWithIntl( + + + + ); + expect(wrapper.find('[data-test-subj="export"]').exists()).toBeTruthy(); + }); +}); diff --git a/src/plugins/share/public/components/share_tabs.tsx b/src/plugins/share/public/components/share_tabs.tsx index fa5c4a1865bf8..d8d9476af9462 100644 --- a/src/plugins/share/public/components/share_tabs.tsx +++ b/src/plugins/share/public/components/share_tabs.tsx @@ -34,7 +34,10 @@ export const ShareMenuTabs = () => { tabs.push(linkTab); - if (shareMenuItems.length > 0) { + const enabledItems = shareMenuItems.filter(({ shareMenuItem }) => !shareMenuItem?.disabled); + + // do not show the export tab if the license is disabled + if (enabledItems.length > 0) { tabs.push(exportTab); } diff --git a/src/plugins/share/tsconfig.json b/src/plugins/share/tsconfig.json index d049342fbe675..8bc8474a84eef 100644 --- a/src/plugins/share/tsconfig.json +++ b/src/plugins/share/tsconfig.json @@ -21,6 +21,10 @@ "@kbn/react-kibana-mount", "@kbn/shared-ux-tabbed-modal", "@kbn/core-theme-browser", + "@kbn/test-jest-helpers", + "@kbn/core-theme-browser-mocks", + "@kbn/core-i18n-browser-mocks", + "@kbn/core-notifications-browser-mocks", ], "exclude": [ "target/**/*", diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_logs_overview/logs_overview.test.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_logs_overview/logs_overview.test.tsx index a0f4ba8e993ff..5de9337689d3a 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_logs_overview/logs_overview.test.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_logs_overview/logs_overview.test.tsx @@ -123,7 +123,7 @@ describe('LogsOverview', () => { }); it('should display a log level badge when available', async () => { - expect(screen.queryByTestId('unifiedDocViewLogsOverviewLogLevel')).toBeInTheDocument(); + expect(screen.queryByTestId('unifiedDocViewLogsOverviewLogLevel-info')).toBeInTheDocument(); }); it('should display a message code block when available', async () => { diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_logs_overview/sub_components/log_level.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_logs_overview/sub_components/log_level.tsx index 5fcfaa871ddf2..215290b0cabeb 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_logs_overview/sub_components/log_level.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_logs_overview/sub_components/log_level.tsx @@ -7,40 +7,19 @@ */ import React from 'react'; -import { EuiBadge, useEuiTheme } from '@elastic/eui'; -import { css } from '@emotion/react'; +import { CSSObject } from '@emotion/react'; import { LogDocumentOverview } from '@kbn/discover-utils'; +import { LogLevelBadge } from '@kbn/discover-utils'; -const LEVEL_DICT = { - error: 'danger', - warn: 'warning', - info: 'primary', - debug: 'accent', -} as const; - -type Level = keyof typeof LEVEL_DICT; +const dataTestSubj = 'unifiedDocViewLogsOverviewLogLevel'; +const badgeCss: CSSObject = { maxWidth: '100px' }; interface LogLevelProps { level: LogDocumentOverview['log.level']; } export function LogLevel({ level }: LogLevelProps) { - const { euiTheme } = useEuiTheme(); - if (!level) return null; - const colorName = LEVEL_DICT[level as Level]; - const computedColor = colorName ? euiTheme.colors[colorName] : null; - return ( - - {level} - - ); + return ; } diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table.tsx index 2b6d1819c9a0a..62f5ed497067b 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table.tsx @@ -141,7 +141,7 @@ export const DocViewerTable = ({ onRemoveColumn, }: DocViewRenderProps) => { const [containerRef, setContainerRef] = useState(null); - const { fieldFormats, storage, uiSettings } = getUnifiedDocViewerServices(); + const { fieldFormats, storage, uiSettings, fieldsMetadata } = getUnifiedDocViewerServices(); const showMultiFields = uiSettings.get(SHOW_MULTIFIELDS); const currentDataViewId = dataView.id!; @@ -387,9 +387,13 @@ export const DocViewerTable = ({ isPinned={pinned} /> - {isDetails && fieldMapping?.customDescription ? ( + {isDetails && !!fieldMapping ? (
- +
) : null} @@ -409,7 +413,7 @@ export const DocViewerTable = ({ return null; }, - [rows, searchText] + [rows, searchText, fieldsMetadata] ); const renderCellPopover = useCallback( 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 a7f75f91d0430..daf67c9e5a330 100644 --- a/src/plugins/unified_histogram/public/services/lens_vis_service.ts +++ b/src/plugins/unified_histogram/public/services/lens_vis_service.ts @@ -455,13 +455,7 @@ export class LensVisService { queryParams: QueryParams; }): Suggestion | undefined => { const { dataView, query, timeRange } = queryParams; - if ( - dataView.isTimeBased() && - query && - isOfAggregateQueryType(query) && - getAggregateQueryMode(query) === 'esql' && - timeRange - ) { + if (dataView.isTimeBased() && query && isOfAggregateQueryType(query) && timeRange) { const isOnHistogramMode = shouldDisplayHistogram(query); if (!isOnHistogramMode) return undefined; diff --git a/src/plugins/unified_search/public/query_string_input/query_bar_top_row.test.tsx b/src/plugins/unified_search/public/query_string_input/query_bar_top_row.test.tsx index 6364c322075a9..92d035a46b100 100644 --- a/src/plugins/unified_search/public/query_string_input/query_bar_top_row.test.tsx +++ b/src/plugins/unified_search/public/query_string_input/query_bar_top_row.test.tsx @@ -310,7 +310,7 @@ describe('QueryBarTopRowTopRow', () => { expect(component.find(QUERY_INPUT_SELECTOR).length).toBe(0); expect(component.find(TEXT_BASED_EDITOR).length).toBe(1); - expect(component.find(TEXT_BASED_EDITOR).prop('detectTimestamp')).toBe(true); + expect(component.find(TEXT_BASED_EDITOR).prop('detectedTimestamp')).toBe('@timestamp'); expect(component.find(TIMEPICKER_SELECTOR).prop('isDisabled')).toBe(false); }); @@ -335,7 +335,7 @@ describe('QueryBarTopRowTopRow', () => { expect(component.find(QUERY_INPUT_SELECTOR).length).toBe(0); expect(component.find(TEXT_BASED_EDITOR).length).toBe(1); - expect(component.find(TEXT_BASED_EDITOR).prop('detectTimestamp')).toBe(false); + expect(component.find(TEXT_BASED_EDITOR).prop('detectedTimestamp')).toBeUndefined(); expect(component.find(TIMEPICKER_SELECTOR).prop('isDisabled')).toMatchInlineSnapshot(` Object { "display": onSubmit({ query: queryRef.current, diff --git a/test/functional/apps/discover/context_awareness/extensions/_get_cell_renderers.ts b/test/functional/apps/discover/context_awareness/extensions/_get_cell_renderers.ts new file mode 100644 index 0000000000000..eadb9db7fd708 --- /dev/null +++ b/test/functional/apps/discover/context_awareness/extensions/_get_cell_renderers.ts @@ -0,0 +1,98 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import kbnRison from '@kbn/rison'; +import expect from '@kbn/expect'; +import type { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const PageObjects = getPageObjects(['common', 'discover', 'unifiedFieldList']); + const esArchiver = getService('esArchiver'); + const testSubjects = getService('testSubjects'); + const dataGrid = getService('dataGrid'); + const dataViews = getService('dataViews'); + const queryBar = getService('queryBar'); + + describe('extension getCellRenderers', () => { + before(async () => { + await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); + }); + + after(async () => { + await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); + }); + + describe('ES|QL mode', () => { + it('should render log.level badge cell', async () => { + const state = kbnRison.encode({ + dataSource: { type: 'esql' }, + query: { + esql: 'from my-example-logs,logstash* | sort @timestamp desc | where `log.level` is not null', + }, + }); + await PageObjects.common.navigateToApp('discover', { + hash: `/?_a=${state}`, + }); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level'); + const firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 0); + const logLevelBadge = await firstCell.findByTestSubject('*logLevelBadgeCell-'); + expect(await logLevelBadge.getVisibleText()).to.be('debug'); + expect(await logLevelBadge.getComputedStyle('background-color')).to.be( + 'rgba(190, 207, 227, 1)' + ); + }); + + it("should not render log.level badge cell if it's not a logs data source", async () => { + const state = kbnRison.encode({ + dataSource: { type: 'esql' }, + query: { + esql: 'from my-example* | sort @timestamp desc | where `log.level` is not null', + }, + }); + await PageObjects.common.navigateToApp('discover', { + hash: `/?_a=${state}`, + }); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level'); + const firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 0); + expect(await firstCell.getVisibleText()).to.be('debug'); + await testSubjects.missingOrFail('*logLevelBadgeCell-'); + }); + }); + + describe('data view mode', () => { + it('should render log.level badge cell', async () => { + await PageObjects.common.navigateToApp('discover'); + await dataViews.switchTo('my-example-logs,logstash*'); + await queryBar.setQuery('log.level:*'); + await queryBar.submitQuery(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level'); + const firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 1); + const logLevelBadge = await firstCell.findByTestSubject('*logLevelBadgeCell-'); + expect(await logLevelBadge.getVisibleText()).to.be('debug'); + expect(await logLevelBadge.getComputedStyle('background-color')).to.be( + 'rgba(190, 207, 227, 1)' + ); + }); + + it("should not render log.level badge cell if it's not a logs data source", async () => { + await PageObjects.common.navigateToApp('discover'); + await dataViews.switchTo('my-example-*'); + await queryBar.setQuery('log.level:*'); + await queryBar.submitQuery(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level'); + const firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 1); + expect(await firstCell.getVisibleText()).to.be('debug'); + await testSubjects.missingOrFail('*logLevelBadgeCell-'); + }); + }); + }); +} diff --git a/test/functional/apps/discover/context_awareness/index.ts b/test/functional/apps/discover/context_awareness/index.ts index b642bcbce7476..3fdd8ab799266 100644 --- a/test/functional/apps/discover/context_awareness/index.ts +++ b/test/functional/apps/discover/context_awareness/index.ts @@ -37,5 +37,6 @@ export default function ({ getService, getPageObjects, loadTestFile }: FtrProvid loadTestFile(require.resolve('./_data_source_profile')); loadTestFile(require.resolve('./extensions/_get_row_indicator_provider')); loadTestFile(require.resolve('./extensions/_get_doc_viewer')); + loadTestFile(require.resolve('./extensions/_get_cell_renderers')); }); } diff --git a/test/functional/apps/discover/esql/_esql_view.ts b/test/functional/apps/discover/esql/_esql_view.ts index 34e74cc4029a8..0753a70837afe 100644 --- a/test/functional/apps/discover/esql/_esql_view.ts +++ b/test/functional/apps/discover/esql/_esql_view.ts @@ -46,12 +46,16 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover'); // and load a set of makelogs data await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); + await esArchiver.load('test/functional/fixtures/es_archiver/kibana_sample_data_flights'); + await kibanaServer.importExport.load( + 'test/functional/fixtures/kbn_archiver/kibana_sample_data_flights_index_pattern' + ); await kibanaServer.uiSettings.replace(defaultSettings); await PageObjects.common.navigateToApp('discover'); await PageObjects.timePicker.setDefaultAbsoluteRange(); }); - describe('test', () => { + describe('ES|QL in Discover', () => { it('should render esql view correctly', async function () { await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); @@ -93,7 +97,43 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(await testSubjects.exists('discoverFieldListPanelEditItem')).to.be(false); }); + it('should not render the histogram for indices with no @timestamp field', async function () { + await PageObjects.discover.selectTextBaseLang(); + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + + const testQuery = `from kibana_sample_data_flights | limit 10`; + + await monacoEditor.setCodeEditorValue(testQuery); + await testSubjects.click('querySubmitButton'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + + expect(await testSubjects.exists('TextBasedLangEditor')).to.be(true); + // I am not rendering the histogram for indices with no @timestamp field + expect(await testSubjects.exists('unifiedHistogramChart')).to.be(false); + }); + + it('should render the histogram for indices with no @timestamp field when the ?earliest, ?latest params are in the query', async function () { + await PageObjects.discover.selectTextBaseLang(); + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + + const testQuery = `from kibana_sample_data_flights | limit 10 | where timestamp >= ?earliest and timestamp <= ?latest`; + + await monacoEditor.setCodeEditorValue(testQuery); + await testSubjects.click('querySubmitButton'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + + const fromTime = 'Apr 10, 2018 @ 00:00:00.000'; + const toTime = 'Nov 15, 2018 @ 00:00:00.000'; + await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); + + expect(await testSubjects.exists('TextBasedLangEditor')).to.be(true); + expect(await testSubjects.exists('unifiedHistogramChart')).to.be(true); + }); + it('should perform test query correctly', async function () { + await PageObjects.timePicker.setDefaultAbsoluteRange(); await PageObjects.discover.selectTextBaseLang(); const testQuery = `from logstash-* | limit 10 | stats countB = count(bytes) by geo.dest | sort countB`; diff --git a/test/functional/apps/discover/group6/_sidebar.ts b/test/functional/apps/discover/group6/_sidebar.ts index a2841bddf8777..d3a7da7b2e92f 100644 --- a/test/functional/apps/discover/group6/_sidebar.ts +++ b/test/functional/apps/discover/group6/_sidebar.ts @@ -442,6 +442,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( '3 selected fields. 3 popular fields. 48 available fields. 5 empty fields. 4 meta fields.' ); + + // verify popular fields were persisted + await browser.refresh(); + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + '3 selected fields. 3 popular fields. 48 available fields. 5 empty fields. 4 meta fields.' + ); }); it('should show selected and available fields in ES|QL mode', async function () { diff --git a/test/functional/apps/discover/group7/_runtime_fields_editor.ts b/test/functional/apps/discover/group7/_runtime_fields_editor.ts index 3028096adc60c..a7f8c677d8657 100644 --- a/test/functional/apps/discover/group7/_runtime_fields_editor.ts +++ b/test/functional/apps/discover/group7/_runtime_fields_editor.ts @@ -113,6 +113,51 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dataGrid.closeFlyout(); }); + it('allows to replace ECS description with a custom field description', async function () { + await PageObjects.unifiedFieldList.clickFieldListItem('@timestamp'); + await retry.waitFor('field popover text', async () => { + return (await testSubjects.getVisibleText('fieldDescription-@timestamp')).startsWith( + 'Date' + ); + }); + await PageObjects.unifiedFieldList.closeFieldPopover(); + // check it in the doc viewer too + await dataGrid.clickRowToggle({ rowIndex: 0 }); + await dataGrid.expandFieldNameCellInFlyout('@timestamp'); + await retry.waitFor('doc viewer popover text', async () => { + return (await testSubjects.getVisibleText('fieldDescription-@timestamp')).startsWith( + 'Date' + ); + }); + await dataGrid.closeFlyout(); + + const customDescription = 'custom @timestamp description here'; + // set a custom description + await PageObjects.discover.editField('@timestamp'); + await fieldEditor.enableCustomDescription(); + await fieldEditor.setCustomDescription(customDescription); + await fieldEditor.save(); + await fieldEditor.waitUntilClosed(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.unifiedFieldList.clickFieldListItem('@timestamp'); + await retry.waitFor('field popover text', async () => { + return ( + (await testSubjects.getVisibleText('fieldDescription-@timestamp')) === customDescription + ); + }); + await PageObjects.unifiedFieldList.closeFieldPopover(); + // check it in the doc viewer too + await dataGrid.clickRowToggle({ rowIndex: 0 }); + await dataGrid.expandFieldNameCellInFlyout('@timestamp'); + await retry.waitFor('doc viewer popover text', async () => { + return ( + (await testSubjects.getVisibleText('fieldDescription-@timestamp')) === customDescription + ); + }); + + await dataGrid.closeFlyout(); + }); + it('should show a validation error when adding a too long custom description to existing fields', async function () { const customDescription = 'custom bytes long description here'.repeat(10); // set a custom description diff --git a/test/functional/apps/management/data_views/_index_pattern_popularity.ts b/test/functional/apps/management/data_views/_index_pattern_popularity.ts index ac95db2d5cad2..1d4062a86f838 100644 --- a/test/functional/apps/management/data_views/_index_pattern_popularity.ts +++ b/test/functional/apps/management/data_views/_index_pattern_popularity.ts @@ -12,6 +12,7 @@ import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const kibanaServer = getService('kibanaServer'); const testSubjects = getService('testSubjects'); + const browser = getService('browser'); const log = getService('log'); const PageObjects = getPageObjects(['settings', 'common']); @@ -58,6 +59,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('can be saved', async function () { // Saving the popularity change await PageObjects.settings.controlChangeSave(); + await browser.refresh(); await PageObjects.settings.openControlsByName(fieldName); const popularity = await PageObjects.settings.getPopularity(); log.debug('popularity = ' + popularity); diff --git a/test/functional/fixtures/kbn_archiver/discover/context_awareness.json b/test/functional/fixtures/kbn_archiver/discover/context_awareness.json index a4a086afc11ce..96388bf2cd384 100644 --- a/test/functional/fixtures/kbn_archiver/discover/context_awareness.json +++ b/test/functional/fixtures/kbn_archiver/discover/context_awareness.json @@ -71,4 +71,29 @@ "updated_at": "2024-06-12T22:23:21.331Z", "updated_by": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0", "version": "WzEwLDFc" +} + +{ + "attributes": { + "allowHidden": false, + "fieldAttrs": "{}", + "fieldFormatMap": "{}", + "fields": "[]", + "name": "my-example-logs,logstash*", + "runtimeFieldMap": "{}", + "sourceFilters": "[]", + "timeFieldName": "@timestamp", + "title": "my-example-logs,logstash*" + }, + "coreMigrationVersion": "8.8.0", + "created_at": "2024-06-12T22:23:41.331Z", + "created_by": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0", + "id": "795df528-add1-491a-8e25-72a862c4bf4e", + "managed": false, + "references": [], + "type": "index-pattern", + "typeMigrationVersion": "8.0.0", + "updated_at": "2024-06-12T22:23:41.331Z", + "updated_by": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0", + "version": "WzEwLDFd" } \ No newline at end of file diff --git a/tsconfig.base.json b/tsconfig.base.json index bbd855176c35a..e58e698258657 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -94,6 +94,8 @@ "@kbn/assets-data-access-plugin/*": ["x-pack/plugins/observability_solution/assets_data_access/*"], "@kbn/audit-log-plugin": ["x-pack/test/security_api_integration/plugins/audit_log"], "@kbn/audit-log-plugin/*": ["x-pack/test/security_api_integration/plugins/audit_log/*"], + "@kbn/avc-banner": ["packages/kbn-avc-banner"], + "@kbn/avc-banner/*": ["packages/kbn-avc-banner/*"], "@kbn/axe-config": ["packages/kbn-axe-config"], "@kbn/axe-config/*": ["packages/kbn-axe-config/*"], "@kbn/babel-preset": ["packages/kbn-babel-preset"], @@ -1468,6 +1470,8 @@ "@kbn/security-plugin-types-public/*": ["x-pack/packages/security/plugin_types_public/*"], "@kbn/security-plugin-types-server": ["x-pack/packages/security/plugin_types_server"], "@kbn/security-plugin-types-server/*": ["x-pack/packages/security/plugin_types_server/*"], + "@kbn/security-solution-distribution-bar": ["x-pack/packages/security-solution/distribution_bar"], + "@kbn/security-solution-distribution-bar/*": ["x-pack/packages/security-solution/distribution_bar/*"], "@kbn/security-solution-ess": ["x-pack/plugins/security_solution_ess"], "@kbn/security-solution-ess/*": ["x-pack/plugins/security_solution_ess/*"], "@kbn/security-solution-features": ["x-pack/packages/security-solution/features"], diff --git a/x-pack/examples/alerting_example/server/plugin.ts b/x-pack/examples/alerting_example/server/plugin.ts index 8aee6fb49dbe5..110071a17fa2d 100644 --- a/x-pack/examples/alerting_example/server/plugin.ts +++ b/x-pack/examples/alerting_example/server/plugin.ts @@ -10,7 +10,7 @@ import { i18n } from '@kbn/i18n'; // import directly to support examples functional tests (@kbn-test/src/functional_tests/lib/babel_register_for_test_plugins.js) import { DEFAULT_APP_CATEGORIES } from '@kbn/core-application-common'; import { PluginSetupContract as AlertingSetup } from '@kbn/alerting-plugin/server'; -import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { ruleType as alwaysFiringRule } from './rule_types/always_firing'; import { ruleType as peopleInSpaceRule } from './rule_types/astros'; diff --git a/x-pack/packages/kbn-data-forge/src/lib/create_events.ts b/x-pack/packages/kbn-data-forge/src/lib/create_events.ts index f787063dfaabc..02fdb51200c2a 100644 --- a/x-pack/packages/kbn-data-forge/src/lib/create_events.ts +++ b/x-pack/packages/kbn-data-forge/src/lib/create_events.ts @@ -117,6 +117,7 @@ export async function createEvents( .flat(); } await queue.push(events); + await queue.drain(); } else { logger.info({ took: 0, latency: 0, indexed: 0 }, 'Indexing 0 documents.'); } diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/actions_connector/post_actions_connector_execute_route.gen.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/actions_connector/post_actions_connector_execute_route.gen.ts index a7f18471dac9d..52174259eeec5 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/actions_connector/post_actions_connector_execute_route.gen.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/actions_connector/post_actions_connector_execute_route.gen.ts @@ -38,8 +38,6 @@ export const ExecuteConnectorRequestBody = z.object({ alertsIndexPattern: z.string().optional(), allow: z.array(z.string()).optional(), allowReplacement: z.array(z.string()).optional(), - isEnabledKnowledgeBase: z.boolean().optional(), - isEnabledRAGAlerts: z.boolean().optional(), replacements: Replacements, size: z.number().optional(), langSmithProject: z.string().optional(), diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/actions_connector/post_actions_connector_execute_route.schema.yaml b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/actions_connector/post_actions_connector_execute_route.schema.yaml index 9ea3c4107c7d1..c21d3b080767f 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/actions_connector/post_actions_connector_execute_route.schema.yaml +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/actions_connector/post_actions_connector_execute_route.schema.yaml @@ -53,10 +53,6 @@ paths: type: array items: type: string - isEnabledKnowledgeBase: - type: boolean - isEnabledRAGAlerts: - type: boolean replacements: $ref: '../conversations/common_attributes.schema.yaml#/components/schemas/Replacements' size: diff --git a/x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings.test.tsx index 9c5bde379e1f4..e708082296112 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings.test.tsx @@ -17,31 +17,6 @@ describe('AlertsSettings', () => { jest.clearAllMocks(); }); - it('updates the knowledgeBase settings when the switch is toggled', () => { - const knowledgeBase: KnowledgeBaseConfig = { - isEnabledRAGAlerts: false, - isEnabledKnowledgeBase: false, - latestAlerts: DEFAULT_LATEST_ALERTS, - }; - const setUpdatedKnowledgeBaseSettings = jest.fn(); - - render( - - ); - - const alertsSwitch = screen.getByTestId('alertsSwitch'); - fireEvent.click(alertsSwitch); - - expect(setUpdatedKnowledgeBaseSettings).toHaveBeenCalledWith({ - isEnabledRAGAlerts: true, - isEnabledKnowledgeBase: false, - latestAlerts: DEFAULT_LATEST_ALERTS, - }); - }); - it('updates the knowledgeBase settings when the alerts range slider is changed', () => { const setUpdatedKnowledgeBaseSettings = jest.fn(); const knowledgeBase: KnowledgeBaseConfig = { @@ -66,22 +41,4 @@ describe('AlertsSettings', () => { latestAlerts: 10, }); }); - - it('enables the alerts range slider when knowledgeBase.isEnabledRAGAlerts is true', () => { - const setUpdatedKnowledgeBaseSettings = jest.fn(); - const knowledgeBase: KnowledgeBaseConfig = { - isEnabledRAGAlerts: true, // <-- true - isEnabledKnowledgeBase: false, - latestAlerts: DEFAULT_LATEST_ALERTS, - }; - - render( - - ); - - expect(screen.getByTestId('alertsRange')).not.toBeDisabled(); - }); }); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings.tsx index b4330bbea0301..be6fea6649bbb 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings.tsx @@ -11,13 +11,11 @@ import { EuiFormRow, EuiRange, EuiSpacer, - EuiSwitch, - EuiSwitchEvent, EuiText, useGeneratedHtmlId, } from '@elastic/eui'; import { css } from '@emotion/react'; -import React, { useCallback } from 'react'; +import React from 'react'; import { KnowledgeBaseConfig } from '../../assistant/types'; import * as i18n from '../../knowledge_base/translations'; @@ -36,16 +34,6 @@ interface Props { const AlertsSettingsComponent = ({ knowledgeBase, setUpdatedKnowledgeBaseSettings }: Props) => { const inputRangeSliderId = useGeneratedHtmlId({ prefix: 'inputRangeSlider' }); - const onEnableAlertsChange = useCallback( - (event: EuiSwitchEvent) => { - setUpdatedKnowledgeBaseSettings({ - ...knowledgeBase, - isEnabledRAGAlerts: event.target.checked, - }); - }, - [knowledgeBase, setUpdatedKnowledgeBaseSettings] - ); - return ( <> - + <> diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/bulk_update_actions_conversations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/bulk_update_actions_conversations.ts index c22095665a229..6fcddfa67c582 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/bulk_update_actions_conversations.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/bulk_update_actions_conversations.ts @@ -139,7 +139,13 @@ export const bulkUpdateConversations = async ( toasts?.addError(error.body && error.body.message ? new Error(error.body.message) : error, { title: i18n.translate('xpack.elasticAssistant.conversations.bulkActionsConversationsError', { defaultMessage: 'Error updating conversations {error}', - values: { error }, + values: { + error: error.message + ? Array.isArray(error.message) + ? error.message.join(',') + : error.message + : error, + }, }), }); } diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.test.tsx index 0e89bc7f5738a..495eed1d16d60 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.test.tsx @@ -36,9 +36,7 @@ const apiConfig: Record<'openai' | 'bedrock' | 'gemini', ApiConfig> = { }; const fetchConnectorArgs: FetchConnectorExecuteAction = { - isEnabledRAGAlerts: false, apiConfig: apiConfig.openai, - isEnabledKnowledgeBase: true, assistantStreamingEnabled: true, http: mockHttp, message: 'This is a test', @@ -75,7 +73,7 @@ describe('API tests', () => { '/internal/elastic_assistant/actions/connector/foo/_execute', { ...staticDefaults, - body: '{"model":"gpt-4","message":"This is a test","subAction":"invokeAI","conversationId":"test","actionTypeId":".gen-ai","replacements":{},"isEnabledKnowledgeBase":true,"isEnabledRAGAlerts":false}', + body: '{"model":"gpt-4","message":"This is a test","subAction":"invokeAI","conversationId":"test","actionTypeId":".gen-ai","replacements":{}}', } ); }); @@ -87,12 +85,12 @@ describe('API tests', () => { '/internal/elastic_assistant/actions/connector/foo/_execute', { ...streamingDefaults, - body: '{"model":"gpt-4","message":"This is a test","subAction":"invokeStream","conversationId":"test","actionTypeId":".gen-ai","replacements":{},"isEnabledKnowledgeBase":true,"isEnabledRAGAlerts":false}', + body: '{"model":"gpt-4","message":"This is a test","subAction":"invokeStream","conversationId":"test","actionTypeId":".gen-ai","replacements":{}}', } ); }); - it('calls the stream API when assistantStreamingEnabled is true and actionTypeId is bedrock and isEnabledKnowledgeBase is true', async () => { + it('calls the stream API when assistantStreamingEnabled is true and actionTypeId is bedrock', async () => { const testProps: FetchConnectorExecuteAction = { ...fetchConnectorArgs, apiConfig: apiConfig.bedrock, @@ -104,53 +102,15 @@ describe('API tests', () => { '/internal/elastic_assistant/actions/connector/foo/_execute', { ...streamingDefaults, - body: '{"message":"This is a test","subAction":"invokeStream","conversationId":"test","actionTypeId":".bedrock","replacements":{},"isEnabledKnowledgeBase":true,"isEnabledRAGAlerts":false}', + body: '{"message":"This is a test","subAction":"invokeStream","conversationId":"test","actionTypeId":".bedrock","replacements":{}}', } ); }); - it('calls the stream API when assistantStreamingEnabled is true and actionTypeId is bedrock and isEnabledKnowledgeBase is false and isEnabledRAGAlerts is true', async () => { - const testProps: FetchConnectorExecuteAction = { - ...fetchConnectorArgs, - apiConfig: apiConfig.bedrock, - isEnabledKnowledgeBase: false, - isEnabledRAGAlerts: true, - }; - - await fetchConnectorExecuteAction(testProps); - - expect(mockHttp.fetch).toHaveBeenCalledWith( - '/internal/elastic_assistant/actions/connector/foo/_execute', - { - ...streamingDefaults, - body: '{"message":"This is a test","subAction":"invokeStream","conversationId":"test","actionTypeId":".bedrock","replacements":{},"isEnabledKnowledgeBase":false,"isEnabledRAGAlerts":true}', - } - ); - }); - - it('calls the stream API when assistantStreamingEnabled is true and actionTypeId is gemini and isEnabledKnowledgeBase is true', async () => { - const testProps: FetchConnectorExecuteAction = { - ...fetchConnectorArgs, - apiConfig: apiConfig.gemini, - }; - - await fetchConnectorExecuteAction(testProps); - - expect(mockHttp.fetch).toHaveBeenCalledWith( - '/internal/elastic_assistant/actions/connector/foo/_execute', - { - ...streamingDefaults, - body: '{"message":"This is a test","subAction":"invokeStream","conversationId":"test","actionTypeId":".gemini","replacements":{},"isEnabledKnowledgeBase":true,"isEnabledRAGAlerts":false}', - } - ); - }); - - it('calls the stream API when assistantStreamingEnabled is true and actionTypeId is gemini and isEnabledKnowledgeBase is false and isEnabledRAGAlerts is true', async () => { + it('calls the stream API when assistantStreamingEnabled is true and actionTypeId is gemini', async () => { const testProps: FetchConnectorExecuteAction = { ...fetchConnectorArgs, apiConfig: apiConfig.gemini, - isEnabledKnowledgeBase: false, - isEnabledRAGAlerts: true, }; await fetchConnectorExecuteAction(testProps); @@ -159,16 +119,15 @@ describe('API tests', () => { '/internal/elastic_assistant/actions/connector/foo/_execute', { ...streamingDefaults, - body: '{"message":"This is a test","subAction":"invokeStream","conversationId":"test","actionTypeId":".gemini","replacements":{},"isEnabledKnowledgeBase":false,"isEnabledRAGAlerts":true}', + body: '{"message":"This is a test","subAction":"invokeStream","conversationId":"test","actionTypeId":".gemini","replacements":{}}', } ); }); - it('calls the stream API when assistantStreamingEnabled is true and actionTypeId is .bedrock and isEnabledKnowledgeBase is false', async () => { + it('calls the stream API when assistantStreamingEnabled is true and actionTypeId is .bedrock', async () => { const testProps: FetchConnectorExecuteAction = { ...fetchConnectorArgs, apiConfig: apiConfig.bedrock, - isEnabledKnowledgeBase: false, }; await fetchConnectorExecuteAction(testProps); @@ -177,7 +136,7 @@ describe('API tests', () => { '/internal/elastic_assistant/actions/connector/foo/_execute', { ...streamingDefaults, - body: '{"message":"This is a test","subAction":"invokeStream","conversationId":"test","actionTypeId":".bedrock","replacements":{},"isEnabledKnowledgeBase":false,"isEnabledRAGAlerts":false}', + body: '{"message":"This is a test","subAction":"invokeStream","conversationId":"test","actionTypeId":".bedrock","replacements":{}}', } ); }); @@ -185,7 +144,6 @@ describe('API tests', () => { it('calls the api with the expected optional request parameters', async () => { const testProps: FetchConnectorExecuteAction = { ...fetchConnectorArgs, - isEnabledRAGAlerts: true, assistantStreamingEnabled: false, alertsIndexPattern: '.alerts-security.alerts-default', replacements: { auuid: 'real.hostname' }, @@ -198,7 +156,7 @@ describe('API tests', () => { '/internal/elastic_assistant/actions/connector/foo/_execute', { ...staticDefaults, - body: '{"model":"gpt-4","message":"This is a test","subAction":"invokeAI","conversationId":"test","actionTypeId":".gen-ai","replacements":{"auuid":"real.hostname"},"isEnabledKnowledgeBase":true,"isEnabledRAGAlerts":true,"alertsIndexPattern":".alerts-security.alerts-default","size":30}', + body: '{"model":"gpt-4","message":"This is a test","subAction":"invokeAI","conversationId":"test","actionTypeId":".gen-ai","replacements":{"auuid":"real.hostname"},"alertsIndexPattern":".alerts-security.alerts-default","size":30}', } ); }); @@ -239,7 +197,6 @@ describe('API tests', () => { const testProps: FetchConnectorExecuteAction = { ...fetchConnectorArgs, - isEnabledKnowledgeBase: false, }; const result = await fetchConnectorExecuteAction(testProps); @@ -258,7 +215,6 @@ describe('API tests', () => { }); const testProps: FetchConnectorExecuteAction = { ...fetchConnectorArgs, - isEnabledKnowledgeBase: false, }; const result = await fetchConnectorExecuteAction(testProps); @@ -281,7 +237,7 @@ describe('API tests', () => { expect(result).toEqual({ response: API_ERROR, isStream: false, isError: true }); }); - it('returns the original when isEnabledKnowledgeBase is true, and `content` is not JSON', async () => { + it('returns the original when `content` is not JSON', async () => { const response = 'plain text content'; (mockHttp.fetch as jest.Mock).mockResolvedValue({ diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.tsx index 8b6bba33f680a..f84c525e2d989 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.tsx @@ -15,9 +15,7 @@ export * from './prompts'; export interface FetchConnectorExecuteAction { conversationId: string; - isEnabledRAGAlerts: boolean; alertsIndexPattern?: string; - isEnabledKnowledgeBase: boolean; assistantStreamingEnabled: boolean; apiConfig: ApiConfig; http: HttpSetup; @@ -40,9 +38,7 @@ export interface FetchConnectorExecuteResponse { export const fetchConnectorExecuteAction = async ({ conversationId, - isEnabledRAGAlerts, alertsIndexPattern, - isEnabledKnowledgeBase, assistantStreamingEnabled, http, message, @@ -56,7 +52,6 @@ export const fetchConnectorExecuteAction = async ({ const isStream = assistantStreamingEnabled; const optionalRequestParams = getOptionalRequestParams({ - isEnabledRAGAlerts, alertsIndexPattern, size, }); @@ -68,8 +63,6 @@ export const fetchConnectorExecuteAction = async ({ conversationId, actionTypeId: apiConfig.actionTypeId, replacements, - isEnabledKnowledgeBase, - isEnabledRAGAlerts, langSmithProject: traceOptions?.langSmithProject === '' ? undefined : traceOptions?.langSmithProject, langSmithApiKey: diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/prompts/bulk_update_prompts.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/prompts/bulk_update_prompts.ts index f9b470c46516c..9b024716ea0da 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/prompts/bulk_update_prompts.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/prompts/bulk_update_prompts.ts @@ -47,7 +47,13 @@ export const bulkUpdatePrompts = async ( toasts?.addError(error.body && error.body.message ? new Error(error.body.message) : error, { title: i18n.translate('xpack.elasticAssistant.prompts.bulkActionspromptsError', { defaultMessage: 'Error updating prompts {error}', - values: { error }, + values: { + error: error.message + ? Array.isArray(error.message) + ? error.message.join(',') + : error.message + : error, + }, }), }); } diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/chat_send/use_chat_send.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/chat_send/use_chat_send.tsx index 5a70b6ad32cd8..c501adc91293f 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/chat_send/use_chat_send.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/chat_send/use_chat_send.tsx @@ -16,7 +16,7 @@ import { useConversation } from '../use_conversation'; import { getCombinedMessage } from '../prompt/helpers'; import { Conversation, useAssistantContext } from '../../..'; import { getMessageFromRawResponse } from '../helpers'; -import { getDefaultSystemPrompt } from '../use_conversation/helpers'; +import { getDefaultSystemPrompt, getDefaultNewSystemPrompt } from '../use_conversation/helpers'; export interface UseChatSendProps { allSystemPrompts: PromptResponse[]; @@ -204,10 +204,11 @@ export const useChatSend = ({ }, [currentConversation, http, removeLastMessage, sendMessage, setCurrentConversation, toasts]); const handleOnChatCleared = useCallback(async () => { - const defaultSystemPromptId = getDefaultSystemPrompt({ - allSystemPrompts, - conversation: currentConversation, - })?.id; + const defaultSystemPromptId = + getDefaultSystemPrompt({ + allSystemPrompts, + conversation: currentConversation, + })?.id ?? getDefaultNewSystemPrompt(allSystemPrompts)?.id; setUserPrompt(''); setSelectedPromptContexts({}); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/flyout/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/flyout/index.tsx index e749fb483d504..f36591e5dbb0e 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/flyout/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/flyout/index.tsx @@ -27,6 +27,7 @@ interface Props { onClose: () => void; onSaveCancelled: () => void; onSaveConfirmed: () => void; + saveButtonDisabled?: boolean; } const FlyoutComponent: React.FC = ({ @@ -36,6 +37,7 @@ const FlyoutComponent: React.FC = ({ onClose, onSaveCancelled, onSaveConfirmed, + saveButtonDisabled = false, }) => { return flyoutVisible ? ( = ({ data-test-subj="save-button" onClick={onSaveConfirmed} iconType="check" + disabled={saveButtonDisabled} fill > {i18n.FLYOUT_SAVE_BUTTON_TITLE} diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/inline_actions/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/inline_actions/index.tsx new file mode 100644 index 0000000000000..6e955dd554d39 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/inline_actions/index.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 { EuiTableActionsColumnType } from '@elastic/eui'; +import { useCallback } from 'react'; +import * as i18n from './translations'; + +interface Props { + disabled?: boolean; + onDelete?: (rowItem: T) => void; + onEdit?: (rowItem: T) => void; +} + +export const useInlineActions = () => { + const getInlineActions = useCallback(({ disabled = false, onDelete, onEdit }: Props) => { + const handleEdit = (rowItem: T) => { + onEdit?.(rowItem); + }; + + const handleDelete = (rowItem: T) => { + onDelete?.(rowItem); + }; + + const actions: EuiTableActionsColumnType = { + name: i18n.ACTIONS_BUTTON, + actions: [ + { + name: i18n.EDIT_BUTTON, + description: i18n.EDIT_BUTTON, + icon: 'pencil', + type: 'icon', + onClick: (rowItem: T) => { + handleEdit(rowItem); + }, + enabled: () => !disabled, + available: () => onEdit != null, + }, + { + name: i18n.DELETE_BUTTON, + description: i18n.DELETE_BUTTON, + icon: 'trash', + type: 'icon', + onClick: (rowItem: T) => { + handleDelete(rowItem); + }, + enabled: ({ isDefault }: { isDefault?: boolean }) => !isDefault && !disabled, + available: () => onDelete != null, + color: 'danger', + }, + ], + }; + return actions; + }, []); + + return getInlineActions; +}; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/row_actions/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/inline_actions/translations.ts similarity index 79% rename from x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/row_actions/translations.ts rename to x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/inline_actions/translations.ts index 1a2430cb6428c..9503c97962bff 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/row_actions/translations.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/inline_actions/translations.ts @@ -20,3 +20,10 @@ export const DELETE_BUTTON = i18n.translate( defaultMessage: 'Delete', } ); + +export const ACTIONS_BUTTON = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.actionsButtonTitle', + { + defaultMessage: 'Actions', + } +); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/row_actions/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/row_actions/index.tsx deleted file mode 100644 index b2d31ec80433f..0000000000000 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/row_actions/index.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 { EuiButtonEmpty, EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiPopover } from '@elastic/eui'; -import React, { useCallback, useState } from 'react'; -import * as i18n from './translations'; - -interface Props { - isDeletable?: boolean; - isEditable?: boolean; - onDelete?: (rowItem: T) => void; - onEdit?: (rowItem: T) => void; - rowItem: T; -} - -type RowActionsComponentType = (props: Props) => JSX.Element; - -const RowActionsComponent = ({ - isDeletable = true, - isEditable = true, - onDelete, - onEdit, - rowItem, -}: Props) => { - const [isPopoverOpen, setIsPopoverOpen] = useState(false); - - const closePopover = useCallback(() => setIsPopoverOpen(false), []); - const handleEdit = useCallback(() => { - closePopover(); - onEdit?.(rowItem); - }, [closePopover, onEdit, rowItem]); - - const handleDelete = useCallback(() => { - closePopover(); - onDelete?.(rowItem); - }, [closePopover, onDelete, rowItem]); - - const onButtonClick = useCallback(() => setIsPopoverOpen((prevState) => !prevState), []); - return onEdit || onDelete ? ( - - } - isOpen={isPopoverOpen} - closePopover={closePopover} - anchorPosition="downLeft" - > - - {onEdit != null && ( - - - {i18n.EDIT_BUTTON} - - - )} - {onDelete != null && ( - - - {i18n.DELETE_BUTTON} - - - )} - - - ) : null; -}; - -// casting to correctly infer the param of onEdit and onDelete when reusing this component -export const RowActions = React.memo(RowActionsComponent) as RowActionsComponentType; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/index.tsx index f1edb5a9dc2a9..9e7e3ae362d84 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/index.tsx @@ -93,7 +93,6 @@ export const ConversationSelectorSettings: React.FC = React.memo( (conversation) => conversation.title === conversationSelectorSettingsOption[0]?.label ) ?? conversationSelectorSettingsOption[0]?.label; - onConversationSelectionChange(newConversation); }, [onConversationSelectionChange, conversations] diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings.test.tsx index 104b55987bc42..9897fc9dc3d97 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings.test.tsx @@ -11,8 +11,8 @@ import { ConversationSettings, ConversationSettingsProps } from './conversation_ import { TestProviders } from '../../../mock/test_providers/test_providers'; import { alertConvo, customConvo, welcomeConvo } from '../../../mock/conversation'; import { mockSystemPrompts } from '../../../mock/system_prompt'; -import { OpenAiProviderType } from '@kbn/stack-connectors-plugin/common/openai/constants'; import { mockConnectors } from '../../../mock/connectors'; +import { HttpSetup } from '@kbn/core/public'; const mockConvos = { '1234': { ...welcomeConvo, id: '1234' }, @@ -24,18 +24,19 @@ const onSelectedConversationChange = jest.fn(); const setConversationSettings = jest.fn(); const setConversationsSettingsBulkActions = jest.fn(); -const testProps = { +const testProps: ConversationSettingsProps = { allSystemPrompts: mockSystemPrompts, + assistantStreamingEnabled: false, + connectors: mockConnectors, conversationSettings: mockConvos, - defaultConnectorId: '123', - defaultProvider: OpenAiProviderType.OpenAi, - http: { basePath: { get: jest.fn() } }, + conversationsSettingsBulkActions: {}, + http: { basePath: { get: jest.fn() } } as unknown as HttpSetup, onSelectedConversationChange, selectedConversation: mockConvos['1234'], + setAssistantStreamingEnabled: jest.fn(), setConversationSettings, - conversationsSettingsBulkActions: {}, setConversationsSettingsBulkActions, -} as unknown as ConversationSettingsProps; +}; jest.mock('../../../connectorland/use_load_connectors', () => ({ useLoadConnectors: () => ({ @@ -113,7 +114,6 @@ jest.mock('../../../connectorland/connector_selector', () => ({ /> ), })); - describe('ConversationSettings', () => { beforeEach(() => { jest.clearAllMocks(); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings.tsx index 1584a46ee687a..d929c132baf43 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings.tsx @@ -17,7 +17,6 @@ import React, { useMemo } from 'react'; import { HttpSetup } from '@kbn/core-http-browser'; -import { ActionTypeRegistryContract } from '@kbn/triggers-actions-ui-plugin/public'; import { PromptResponse } from '@kbn/elastic-assistant-common'; import { Conversation } from '../../../..'; import * as i18n from './translations'; @@ -33,7 +32,6 @@ import { useConversationChanged } from './use_conversation_changed'; import { getConversationApiConfig } from '../../use_conversation/helpers'; export interface ConversationSettingsProps { - actionTypeRegistry: ActionTypeRegistryContract; allSystemPrompts: PromptResponse[]; connectors?: AIConnector[]; conversationSettings: Record; @@ -128,6 +126,7 @@ export const ConversationSettings: React.FC = React.m selectedConversation={selectedConversationWithApiConfig} setConversationSettings={setConversationSettings} setConversationsSettingsBulkActions={setConversationsSettingsBulkActions} + onSelectedConversationChange={onSelectedConversationChange} /> diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings_editor.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings_editor.tsx index cf8275203090b..85b6360b409be 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings_editor.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings_editor.tsx @@ -36,6 +36,7 @@ export interface ConversationSettingsEditorProps { setConversationsSettingsBulkActions: React.Dispatch< React.SetStateAction >; + onSelectedConversationChange: (conversation?: Conversation) => void; } /** @@ -51,11 +52,11 @@ export const ConversationSettingsEditor: React.FC { const { data: connectors, isSuccess: areConnectorsFetched } = useLoadConnectors({ http, }); - const selectedSystemPrompt = useMemo(() => { return getDefaultSystemPrompt({ allSystemPrompts, conversation: selectedConversation }); }, [allSystemPrompts, selectedConversation]); @@ -95,13 +96,14 @@ export const ConversationSettingsEditor: React.FC
@@ -290,7 +297,7 @@ export const ConversationSettingsEditor: React.FC } diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/translations.ts index 300176480ba1e..55852fc2a1bad 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/translations.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/translations.ts @@ -52,14 +52,14 @@ export const SETTINGS_PROMPT_TITLE = i18n.translate( export const SETTINGS_PROMPT_HELP_TEXT_TITLE = i18n.translate( 'xpack.elasticAssistant.assistant.conversations.settings.promptHelpTextTitle', { - defaultMessage: 'Context provided as part of every conversation', + defaultMessage: 'Context provided as part of every conversation.', } ); export const STREAMING_TITLE = i18n.translate( 'xpack.elasticAssistant.assistant.conversations.settings.streamingTitle', { - defaultMessage: 'Streaming', + defaultMessage: 'STREAMING', } ); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/use_conversation_changed.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/use_conversation_changed.tsx index 78209d95c75fa..f0bc2fbc44ac2 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/use_conversation_changed.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/use_conversation_changed.tsx @@ -84,7 +84,6 @@ export const useConversationChanged = ({ }; }); } - onSelectedConversationChange({ ...newSelectedConversation, id: newSelectedConversation.id || newSelectedConversation.title, diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings_management/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings_management/index.tsx index 10608502e70d3..0f4cba3a29957 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings_management/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings_management/index.tsx @@ -5,45 +5,45 @@ * 2.0. */ -import { EuiPanel, EuiSpacer, EuiConfirmModal, EuiInMemoryTable } from '@elastic/eui'; -import React, { useCallback, useMemo, useState } from 'react'; +import { + EuiPanel, + EuiSpacer, + EuiConfirmModal, + EuiInMemoryTable, + EuiTitle, + EuiText, +} from '@elastic/eui'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import { PromptResponse } from '@kbn/elastic-assistant-common'; import { Conversation } from '../../../assistant_context/types'; import { ConversationTableItem, useConversationsTable } from './use_conversations_table'; import { ConversationStreamingSwitch } from '../conversation_settings/conversation_streaming_switch'; import { AIConnector } from '../../../connectorland/connector_selector'; import * as i18n from './translations'; -import { ConversationsBulkActions } from '../../api'; +import { + FetchConversationsResponse, + useFetchCurrentUserConversations, + useFetchPrompts, +} from '../../api'; import { useAssistantContext } from '../../../assistant_context'; import { useConversationDeleted } from '../conversation_settings/use_conversation_deleted'; import { useFlyoutModalVisibility } from '../../common/components/assistant_settings_management/flyout/use_flyout_modal_visibility'; import { Flyout } from '../../common/components/assistant_settings_management/flyout'; -import { CANCEL, DELETE } from '../../settings/translations'; +import { CANCEL, DELETE, SETTINGS_UPDATED_TOAST_TITLE } from '../../settings/translations'; import { ConversationSettingsEditor } from '../conversation_settings/conversation_settings_editor'; import { useConversationChanged } from '../conversation_settings/use_conversation_changed'; import { CONVERSATION_TABLE_SESSION_STORAGE_KEY } from '../../../assistant_context/constants'; import { useSessionPagination } from '../../common/components/assistant_settings_management/pagination/use_session_pagination'; import { DEFAULT_PAGE_SIZE } from '../../settings/const'; +import { useSettingsUpdater } from '../../settings/use_settings_updater/use_settings_updater'; +import { mergeBaseWithPersistedConversations } from '../../helpers'; +import { AssistantSettingsBottomBar } from '../../settings/assistant_settings_bottom_bar'; interface Props { - allSystemPrompts: PromptResponse[]; - assistantStreamingEnabled: boolean; connectors: AIConnector[] | undefined; - conversationSettings: Record; - conversationsSettingsBulkActions: ConversationsBulkActions; - conversationsLoaded: boolean; defaultConnector?: AIConnector; - handleSave: (shouldRefetchConversation?: boolean) => void; + defaultSelectedConversation: Conversation; isDisabled?: boolean; - onCancelClick: () => void; - setAssistantStreamingEnabled: React.Dispatch>; - setConversationSettings: React.Dispatch>>; - setConversationsSettingsBulkActions: React.Dispatch< - React.SetStateAction - >; - selectedConversation: Conversation | undefined; - onSelectedConversationChange: (conversation?: Conversation) => void; } export const DEFAULT_TABLE_OPTIONS = { @@ -52,23 +52,112 @@ export const DEFAULT_TABLE_OPTIONS = { }; const ConversationSettingsManagementComponent: React.FC = ({ - allSystemPrompts, - assistantStreamingEnabled, connectors, defaultConnector, - conversationSettings, - conversationsSettingsBulkActions, - conversationsLoaded, - handleSave, + defaultSelectedConversation, isDisabled, - onSelectedConversationChange, - onCancelClick, - selectedConversation, - setAssistantStreamingEnabled, - setConversationSettings, - setConversationsSettingsBulkActions, }) => { - const { http, nameSpace, actionTypeRegistry } = useAssistantContext(); + const { + actionTypeRegistry, + assistantAvailability: { isAssistantEnabled }, + baseConversations, + http, + nameSpace, + toasts, + } = useAssistantContext(); + + const onFetchedConversations = useCallback( + (conversationsData: FetchConversationsResponse): Record => + mergeBaseWithPersistedConversations(baseConversations, conversationsData), + [baseConversations] + ); + + const { data: allPrompts, isFetched: promptsLoaded, refetch: refetchPrompts } = useFetchPrompts(); + + const { + data: conversations, + isFetched: conversationsLoaded, + refetch: refetchConversations, + } = useFetchCurrentUserConversations({ + http, + onFetch: onFetchedConversations, + isAssistantEnabled, + }); + + const refetchAll = useCallback(() => { + refetchPrompts(); + refetchConversations(); + }, [refetchPrompts, refetchConversations]); + + const { + systemPromptSettings: allSystemPrompts, + assistantStreamingEnabled, + conversationSettings, + conversationsSettingsBulkActions, + resetSettings, + saveSettings, + setConversationSettings, + setConversationsSettingsBulkActions, + setUpdatedAssistantStreamingEnabled, + } = useSettingsUpdater(conversations, allPrompts, conversationsLoaded, promptsLoaded); + + const [hasPendingChanges, setHasPendingChanges] = useState(false); + + const handleSave = useCallback( + async (param?: { callback?: () => void }) => { + const isSuccess = await saveSettings(); + if (isSuccess) { + toasts?.addSuccess({ + iconType: 'check', + title: SETTINGS_UPDATED_TOAST_TITLE, + }); + setHasPendingChanges(false); + param?.callback?.(); + } else { + resetSettings(); + } + }, + [resetSettings, saveSettings, toasts] + ); + + const setAssistantStreamingEnabled = useCallback( + (value) => { + setHasPendingChanges(true); + setUpdatedAssistantStreamingEnabled(value); + }, + [setUpdatedAssistantStreamingEnabled] + ); + + const onSaveButtonClicked = useCallback(() => { + handleSave({ callback: refetchAll }); + }, [handleSave, refetchAll]); + + const onCancelClick = useCallback(() => { + resetSettings(); + setHasPendingChanges(false); + }, [resetSettings]); + + // Local state for saving previously selected items so tab switching is friendlier + // Conversation Selection State + const [selectedConversation, setSelectedConversation] = useState(() => { + return conversationSettings[defaultSelectedConversation.title]; + }); + + const onSelectedConversationChange = useCallback((conversation?: Conversation) => { + setSelectedConversation(conversation); + }, []); + + useEffect(() => { + if (selectedConversation != null) { + const newConversation = + conversationSettings[selectedConversation.id] || + conversationSettings[selectedConversation.title]; + setSelectedConversation( + // conversationSettings has title as key, sometime has id as key + newConversation + ); + } + }, [conversationSettings, selectedConversation]); const { isFlyoutOpen: editFlyoutVisible, @@ -124,12 +213,13 @@ const ConversationSettingsManagementComponent: React.FC = ({ return; } closeConfirmModal(); - handleSave(true); + handleSave({ callback: refetchAll }); setConversationsSettingsBulkActions({}); }, [ closeConfirmModal, conversationsSettingsBulkActions, handleSave, + refetchAll, setConversationsSettingsBulkActions, ]); @@ -162,9 +252,9 @@ const ConversationSettingsManagementComponent: React.FC = ({ const onSaveConfirmed = useCallback(() => { closeEditFlyout(); - handleSave(true); + handleSave({ callback: refetchAll }); setConversationsSettingsBulkActions({}); - }, [closeEditFlyout, handleSave, setConversationsSettingsBulkActions]); + }, [closeEditFlyout, handleSave, refetchAll, setConversationsSettingsBulkActions]); const columns = useMemo( () => @@ -191,12 +281,21 @@ const ConversationSettingsManagementComponent: React.FC = ({ return ( <> + +

{i18n.CONVERSATIONS_SETTINGS_TITLE}

+
- + + +

{i18n.CONVERSATIONS_LIST_TITLE}

+
+ + {i18n.CONVERSATIONS_LIST_DESCRIPTION} + = ({ onSaveConfirmed={onSaveConfirmed} onSaveCancelled={onSaveCancelled} title={selectedConversation?.title ?? i18n.CONVERSATIONS_FLYOUT_DEFAULT_TITLE} + saveButtonDisabled={ + selectedConversation?.title == null || selectedConversation?.title === '' + } > = ({ selectedConversation={selectedConversation} setConversationSettings={setConversationSettings} setConversationsSettingsBulkActions={setConversationsSettingsBulkActions} + onSelectedConversationChange={onSelectedConversationChange} /> )} @@ -240,6 +343,11 @@ const ConversationSettingsManagementComponent: React.FC = ({

)} + ); }; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings_management/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings_management/translations.ts index 5761ba8e6e99f..260f095f9a128 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings_management/translations.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings_management/translations.ts @@ -7,10 +7,31 @@ import { i18n } from '@kbn/i18n'; -export const CONVERSATIONS_TABLE_COLUMN_NAME = i18n.translate( - 'xpack.elasticAssistant.assistant.conversationSettings.column.name', +export const CONVERSATIONS_SETTINGS_TITLE = i18n.translate( + 'xpack.elasticAssistant.assistant.conversationSettings.title', { - defaultMessage: 'Name', + defaultMessage: 'Settings', + } +); + +export const CONVERSATIONS_LIST_TITLE = i18n.translate( + 'xpack.elasticAssistant.assistant.conversationSettings.list.title', + { + defaultMessage: 'Conversation list', + } +); + +export const CONVERSATIONS_LIST_DESCRIPTION = i18n.translate( + 'xpack.elasticAssistant.assistant.conversationSettings.list.description', + { + defaultMessage: 'Create and manage conversations with the Elastic AI Assistant.', + } +); + +export const CONVERSATIONS_TABLE_COLUMN_TITLE = i18n.translate( + 'xpack.elasticAssistant.assistant.conversationSettings.column.Title', + { + defaultMessage: 'Title', } ); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings_management/use_conversations_table.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings_management/use_conversations_table.test.tsx index 465ffa792fb0b..1c293cf061c29 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings_management/use_conversations_table.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings_management/use_conversations_table.test.tsx @@ -14,8 +14,6 @@ import { alertConvo, welcomeConvo, customConvo } from '../../../mock/conversatio import { mockActionTypes, mockConnectors } from '../../../mock/connectors'; import { mockSystemPrompts } from '../../../mock/system_prompt'; import { ActionTypeRegistryContract } from '@kbn/triggers-actions-ui-plugin/public'; -import * as i18n from './translations'; -import { EuiTableFieldDataColumnType } from '@elastic/eui'; const mockActionTypeRegistry: ActionTypeRegistryContract = { has: jest @@ -42,17 +40,11 @@ describe('useConversationsTable', () => { expect(columns).toHaveLength(5); - expect(columns[0].name).toBe(i18n.CONVERSATIONS_TABLE_COLUMN_NAME); - expect((columns[1] as EuiTableFieldDataColumnType).field).toBe( - 'systemPromptTitle' - ); - expect((columns[2] as EuiTableFieldDataColumnType).field).toBe( - 'connectorTypeTitle' - ); - expect((columns[3] as EuiTableFieldDataColumnType).field).toBe( - 'updatedAt' - ); - expect(columns[4].name).toBe(i18n.CONVERSATIONS_TABLE_COLUMN_ACTIONS); + expect(columns[0].name).toBe('Title'); + expect(columns[1].name).toBe('System prompt'); + expect(columns[2].name).toBe('Connector'); + expect(columns[3].name).toBe('Date updated'); + expect(columns[4].name).toBe('Actions'); }); it('should return a list of conversations', () => { @@ -78,14 +70,14 @@ describe('useConversationsTable', () => { expect(conversationsList[0].title).toBe(alertConvo.title); expect(conversationsList[0].connectorTypeTitle).toBe('OpenAI'); - expect(conversationsList[0].systemPromptTitle).toBe('Mock system prompt'); + expect(conversationsList[0].systemPromptTitle).toBeUndefined(); expect(conversationsList[1].title).toBe(welcomeConvo.title); expect(conversationsList[1].connectorTypeTitle).toBe('OpenAI'); - expect(conversationsList[1].systemPromptTitle).toBe('Mock system prompt'); + expect(conversationsList[1].systemPromptTitle).toBeUndefined(); expect(conversationsList[2].title).toBe(customConvo.title); expect(conversationsList[2].connectorTypeTitle).toBe('OpenAI'); - expect(conversationsList[2].systemPromptTitle).toBe('Mock system prompt'); + expect(conversationsList[2].systemPromptTitle).toBeUndefined(); }); }); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings_management/use_conversations_table.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings_management/use_conversations_table.tsx index 446fb33ebb9e9..0d253be5d2651 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings_management/use_conversations_table.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings_management/use_conversations_table.tsx @@ -15,12 +15,9 @@ import { PromptResponse } from '@kbn/elastic-assistant-common'; import { Conversation } from '../../../assistant_context/types'; import { AIConnector } from '../../../connectorland/connector_selector'; import { getConnectorTypeTitle } from '../../../connectorland/helpers'; -import { - getConversationApiConfig, - getInitialDefaultSystemPrompt, -} from '../../use_conversation/helpers'; +import { getConversationApiConfig } from '../../use_conversation/helpers'; import * as i18n from './translations'; -import { RowActions } from '../../common/components/assistant_settings_management/row_actions'; +import { useInlineActions } from '../../common/components/assistant_settings_management/inline_actions'; const emptyConversations = {}; @@ -38,6 +35,7 @@ export type ConversationTableItem = Conversation & { }; export const useConversationsTable = () => { + const getActions = useInlineActions(); const getColumns = useCallback( ({ onDeleteActionClicked, @@ -45,7 +43,7 @@ export const useConversationsTable = () => { }): Array> => { return [ { - name: i18n.CONVERSATIONS_TABLE_COLUMN_NAME, + name: i18n.CONVERSATIONS_TABLE_COLUMN_TITLE, render: (conversation: ConversationTableItem) => ( onEditActionClicked(conversation)}> {conversation.title} @@ -87,24 +85,16 @@ export const useConversationsTable = () => { sortable: true, }, { - name: i18n.CONVERSATIONS_TABLE_COLUMN_ACTIONS, width: '120px', align: 'center', - render: (conversation: ConversationTableItem) => { - const isDeletable = !conversation.isDefault; - return ( - - rowItem={conversation} - onDelete={isDeletable ? onDeleteActionClicked : undefined} - onEdit={onEditActionClicked} - isDeletable={isDeletable} - /> - ); - }, + ...getActions({ + onDelete: onDeleteActionClicked, + onEdit: onEditActionClicked, + }), }, ]; }, - [] + [getActions] ); const getConversationsList = useCallback( ({ @@ -129,16 +119,8 @@ export const useConversationsTable = () => { const systemPrompt: PromptResponse | undefined = allSystemPrompts.find( ({ id }) => id === conversation.apiConfig?.defaultSystemPromptId ); - const defaultSystemPrompt = getInitialDefaultSystemPrompt({ - allSystemPrompts, - conversation, - }); - const systemPromptTitle = - systemPrompt?.name || - systemPrompt?.id || - defaultSystemPrompt?.name || - defaultSystemPrompt?.id; + const systemPromptTitle = systemPrompt?.name || systemPrompt?.id; return { ...conversation, diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/helpers.test.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/helpers.test.ts index b4ed11a82df9e..e12fe556f5ba4 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/helpers.test.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/helpers.test.ts @@ -163,21 +163,8 @@ describe('helpers', () => { }); describe('getOptionalRequestParams', () => { - it('should return an empty object when alerts is false', () => { - const params = { - isEnabledRAGAlerts: false, // <-- false - alertsIndexPattern: 'indexPattern', - size: 10, - }; - - const result = getOptionalRequestParams(params); - - expect(result).toEqual({}); - }); - it('should return the optional request params when alerts is true', () => { const params = { - isEnabledRAGAlerts: true, alertsIndexPattern: 'indexPattern', size: 10, }; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/helpers.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/helpers.ts index e7dad6dabd4fe..54ca317a6fe5b 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/helpers.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/helpers.ts @@ -100,22 +100,15 @@ interface OptionalRequestParams { } export const getOptionalRequestParams = ({ - isEnabledRAGAlerts, alertsIndexPattern, size, }: { - isEnabledRAGAlerts: boolean; alertsIndexPattern?: string; size?: number; }): OptionalRequestParams => { const optionalAlertsIndexPattern = alertsIndexPattern ? { alertsIndexPattern } : undefined; const optionalSize = size ? { size } : undefined; - // the settings toggle must be enabled: - if (!isEnabledRAGAlerts) { - return {}; // don't send any optional params - } - return { ...optionalAlertsIndexPattern, ...optionalSize, diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/index.tsx index 7626f481f15d2..92b285c7eca55 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/index.tsx @@ -80,7 +80,7 @@ import { Conversation } from '../assistant_context/types'; import { getGenAiConfig } from '../connectorland/helpers'; import { AssistantAnimatedIcon } from './assistant_animated_icon'; import { useFetchAnonymizationFields } from './api/anonymization_fields/use_fetch_anonymization_fields'; -import { InstallKnowledgeBaseButton } from '../knowledge_base/install_knowledge_base_button'; +import { SetupKnowledgeBaseButton } from '../knowledge_base/setup_knowledge_base_button'; import { useFetchPrompts } from './api/prompts/use_fetch_prompts'; export interface Props { @@ -798,7 +798,7 @@ const AssistantComponent: React.FC = ({ /> - + diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/select_system_prompt/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/select_system_prompt/index.tsx index 0f10cf6d3063f..fbe0f40320c4c 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/select_system_prompt/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/select_system_prompt/index.tsx @@ -43,6 +43,9 @@ export interface Props { isSettingsModalVisible: boolean; setIsSettingsModalVisible: React.Dispatch>; onSystemPromptSelectionChange?: (promptId: string | undefined) => void; + onSelectedConversationChange?: (result: Conversation) => void; + setConversationSettings?: React.Dispatch>>; + setConversationsSettingsBulkActions?: React.Dispatch>; } const ADD_NEW_SYSTEM_PROMPT = 'ADD_NEW_SYSTEM_PROMPT'; @@ -59,6 +62,9 @@ const SelectSystemPromptComponent: React.FC = ({ isSettingsModalVisible, onSystemPromptSelectionChange, setIsSettingsModalVisible, + onSelectedConversationChange, + setConversationSettings, + setConversationsSettingsBulkActions, }) => { const { setSelectedSettingsTab } = useAssistantContext(); const { setApiConfig } = useConversation(); @@ -74,15 +80,16 @@ const SelectSystemPromptComponent: React.FC = ({ // Write the selected system prompt to the conversation config const setSelectedSystemPrompt = useCallback( - (promptId?: string) => { + async (promptId?: string) => { if (conversation && conversation.apiConfig) { - setApiConfig({ + const result = await setApiConfig({ conversation, apiConfig: { ...conversation.apiConfig, defaultSystemPromptId: promptId, }, }); + return result; } }, [conversation, setApiConfig] @@ -112,7 +119,7 @@ const SelectSystemPromptComponent: React.FC = ({ const options = useMemo(() => getOptions({ prompts: allSystemPrompts }), [allSystemPrompts]); const onChange = useCallback( - (selectedSystemPromptId) => { + async (selectedSystemPromptId) => { if (selectedSystemPromptId === ADD_NEW_SYSTEM_PROMPT) { setIsSettingsModalVisible(true); setSelectedSettingsTab(SYSTEM_PROMPTS_TAB); @@ -122,10 +129,30 @@ const SelectSystemPromptComponent: React.FC = ({ if (onSystemPromptSelectionChange != null) { onSystemPromptSelectionChange(selectedSystemPromptId); } - setSelectedSystemPrompt(selectedSystemPromptId); + const result = await setSelectedSystemPrompt(selectedSystemPromptId); + if (result) { + setConversationSettings?.((prev: Record) => { + const newConversationsSettings = Object.entries(prev).reduce< + Record + >((acc, [key, convo]) => { + if (result.title === convo.title) { + acc[result.id] = result; + } else { + acc[key] = convo; + } + return acc; + }, {}); + return newConversationsSettings; + }); + onSelectedConversationChange?.(result); + setConversationsSettingsBulkActions?.({}); + } }, [ + onSelectedConversationChange, onSystemPromptSelectionChange, + setConversationSettings, + setConversationsSettingsBulkActions, setIsSettingsModalVisible, setSelectedSettingsTab, setSelectedSystemPrompt, diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/system_prompt_editor.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/system_prompt_editor.tsx index fecb2ed401a4b..be072790bf7fc 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/system_prompt_editor.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/system_prompt_editor.tsx @@ -32,7 +32,10 @@ import { TEST_IDS } from '../../../constants'; import { ConversationsBulkActions } from '../../../api'; import { getSelectedConversations } from '../system_prompt_settings_management/utils'; import { useSystemPromptEditor } from './use_system_prompt_editor'; -import { getConversationApiConfig } from '../../../use_conversation/helpers'; +import { + getConversationApiConfig, + getFallbackDefaultSystemPrompt, +} from '../../../use_conversation/helpers'; interface Props { connectors: AIConnector[] | undefined; @@ -99,7 +102,7 @@ export const SystemPromptEditorComponent: React.FC = ({ }); const existingPrompt = systemPromptSettings.find((sp) => sp.id === selectedSystemPrompt.id); if (existingPrompt) { - setPromptsBulkActions({ + const newBulkActions = { ...promptsBulkActions, ...(selectedSystemPrompt.name !== selectedSystemPrompt.id ? { @@ -124,7 +127,8 @@ export const SystemPromptEditorComponent: React.FC = ({ }, ], }), - }); + }; + setPromptsBulkActions(newBulkActions); } } }, @@ -159,20 +163,15 @@ export const SystemPromptEditorComponent: React.FC = ({ const selectedConversations = useMemo(() => { return selectedSystemPrompt != null - ? getSelectedConversations( - systemPromptSettings, - conversationsWithApiConfig, - selectedSystemPrompt.id - ) + ? getSelectedConversations(conversationsWithApiConfig, selectedSystemPrompt.id) : []; - }, [conversationsWithApiConfig, selectedSystemPrompt, systemPromptSettings]); + }, [conversationsWithApiConfig, selectedSystemPrompt]); const handleConversationSelectionChange = useCallback( (currentPromptConversations: Conversation[]) => { const currentPromptConversationTitles = currentPromptConversations.map( (convo) => convo.title ); - const getDefaultSystemPromptId = (convo: Conversation) => currentPromptConversationTitles.includes(convo.title) ? selectedSystemPrompt?.id @@ -180,7 +179,7 @@ export const SystemPromptEditorComponent: React.FC = ({ ? // remove the default System Prompt if it is assigned to a conversation // but that conversation is not in the currentPromptConversationList // This means conversation was removed in the current transaction - systemPromptSettings?.[0].id + undefined : // leave it as it is .. if that conversation was neither added nor removed. convo.apiConfig?.defaultSystemPromptId; @@ -194,23 +193,26 @@ export const SystemPromptEditorComponent: React.FC = ({ * through each conversation adds/removed the selected prompt on each conversation. * * */ - Object.values(prev).map((convo) => ({ - ...convo, - ...(convo.apiConfig - ? { - apiConfig: { - ...convo.apiConfig, - defaultSystemPromptId: getDefaultSystemPromptId(convo), - }, - } - : { - apiConfig: { - defaultSystemPromptId: getDefaultSystemPromptId(convo), - connectorId: defaultConnector?.id ?? '', - actionTypeId: defaultConnector?.actionTypeId ?? '', - }, - }), - })) + Object.values(prev).map((convo) => { + const newConversationSetting = { + ...convo, + ...(convo.apiConfig + ? { + apiConfig: { + ...convo.apiConfig, + defaultSystemPromptId: getDefaultSystemPromptId(convo), + }, + } + : { + apiConfig: { + defaultSystemPromptId: getDefaultSystemPromptId(convo), + connectorId: defaultConnector?.id ?? '', + actionTypeId: defaultConnector?.actionTypeId ?? '', + }, + }), + }; + return newConversationSetting; + }) ) ); @@ -226,7 +228,9 @@ export const SystemPromptEditorComponent: React.FC = ({ conversation: convo, defaultConnector, }).apiConfig, - defaultSystemPromptId: getDefaultSystemPromptId(convo), + defaultSystemPromptId: + getDefaultSystemPromptId(convo) ?? + getFallbackDefaultSystemPrompt({ allSystemPrompts: systemPromptSettings })?.id, }, }; } @@ -266,7 +270,6 @@ export const SystemPromptEditorComponent: React.FC = ({ ...updateOperation, }; }); - setConversationsSettingsBulkActions(updatedConversationsSettingsBulkActions); } }, @@ -291,6 +294,21 @@ export const SystemPromptEditorComponent: React.FC = ({ const handleNewConversationDefaultChange = useCallback( (e) => { const isChecked = e.target.checked; + const defaultNewSystemPrompts = systemPromptSettings.filter( + (p) => p.isNewConversationDefault + ); + + const shouldCreateNewDefaultSystemPrompts = (sp?: { name: string; id: string }) => + sp?.name === sp?.id; // Prompts before preserving have the SAME name and id + + const shouldUpdateNewDefaultSystemPrompts = (sp?: { name: string; id: string }) => + sp?.name !== sp?.id; // Prompts after preserving have different name and id + + const shouldCreateSelectedSystemPrompt = + selectedSystemPrompt?.name === selectedSystemPrompt?.id; + + const shouldUpdateSelectedSystemPrompt = + selectedSystemPrompt?.name !== selectedSystemPrompt?.id; if (selectedSystemPrompt != null) { setUpdatedSystemPromptSettings((prev) => { @@ -301,39 +319,60 @@ export const SystemPromptEditorComponent: React.FC = ({ }; }); }); - setPromptsBulkActions({ - ...promptsBulkActions, - ...(selectedSystemPrompt.name !== selectedSystemPrompt.id - ? { - update: [ - ...(promptsBulkActions.update ?? []).filter( - (p) => p.id !== selectedSystemPrompt.id - ), - { - ...selectedSystemPrompt, - isNewConversationDefault: isChecked, - }, - ], - } - : { - create: [ - ...(promptsBulkActions.create ?? []).filter( - (p) => p.name !== selectedSystemPrompt.name - ), - { - ...selectedSystemPrompt, - isNewConversationDefault: isChecked, - }, - ], - }), + // Update and Create prompts can happen at the same time, as we have to unchecked the previous default prompt + // Each prompt can be updated or created + setPromptsBulkActions(() => { + const newBulkActions = { + update: [ + ...defaultNewSystemPrompts + .filter( + (p) => p.id !== selectedSystemPrompt.id && shouldUpdateNewDefaultSystemPrompts(p) + ) + .map((p) => ({ + ...p, + isNewConversationDefault: false, + })), + + ...(shouldUpdateSelectedSystemPrompt + ? [ + { + ...selectedSystemPrompt, + isNewConversationDefault: isChecked, + }, + ] + : []), + ], + create: [ + ...defaultNewSystemPrompts + .filter( + (p) => + p.name !== selectedSystemPrompt.name && shouldCreateNewDefaultSystemPrompts(p) + ) + .map((p) => ({ + ...p, + isNewConversationDefault: false, + })), + + ...(shouldCreateSelectedSystemPrompt + ? [ + { + ...selectedSystemPrompt, + isNewConversationDefault: isChecked, + }, + ] + : []), + ], + }; + + return newBulkActions; }); } }, [ - promptsBulkActions, selectedSystemPrompt, setPromptsBulkActions, setUpdatedSystemPromptSettings, + systemPromptSettings, ] ); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/system_prompt_selector/system_prompt_selector.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/system_prompt_selector/system_prompt_selector.tsx index ae5fce935cfe3..4e97ca36f1198 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/system_prompt_selector/system_prompt_selector.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/system_prompt_selector/system_prompt_selector.tsx @@ -87,6 +87,7 @@ export const SystemPromptSelector: React.FC = React.memo( ? undefined : systemPrompts.find((sp) => sp.name === systemPromptSelectorOption[0]?.label) ?? systemPromptSelectorOption[0]?.label; + onSystemPromptSelectionChange(newSystemPrompt); }, [onSystemPromptSelectionChange, resetSettings, systemPrompts] diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/translations.ts index 06544b98a68bd..92837d970864c 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/translations.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/translations.ts @@ -65,7 +65,7 @@ export const SYSTEM_PROMPT_DEFAULT_NEW_CONVERSATION = i18n.translate( export const SYSTEM_PROMPT_DEFAULT_CONVERSATIONS_HELP_TEXT = i18n.translate( 'xpack.elasticAssistant.assistant.promptEditor.systemPrompt.settings.defaultConversationsHelpText', { - defaultMessage: 'Conversations that should use this System Prompt by default', + defaultMessage: 'Conversations that should use this System Prompt by default.', } ); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/use_system_prompt_editor.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/use_system_prompt_editor.tsx index ec77de113b5d9..72e193142e998 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/use_system_prompt_editor.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/use_system_prompt_editor.tsx @@ -52,14 +52,17 @@ export const useSystemPromptEditor = ({ }); if (isNew) { - setPromptsBulkActions({ - ...promptsBulkActions, - create: [ - ...(promptsBulkActions.create ?? []), - { - ...newSelectedSystemPrompt, - }, - ], + setPromptsBulkActions((prev) => { + const newBulkActions = { + ...prev, + create: [ + ...(promptsBulkActions.create ?? []), + { + ...newSelectedSystemPrompt, + }, + ], + }; + return newBulkActions; }); } } diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/index.tsx index 14b6ecb868ead..69ec81547912e 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/index.tsx @@ -13,23 +13,28 @@ import { EuiFlexGroup, EuiFlexItem, EuiSpacer, + EuiText, } from '@elastic/eui'; -import React, { useCallback, useMemo, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import { PromptResponse } from '@kbn/elastic-assistant-common'; import { - PromptResponse, - PerformBulkActionRequestBody as PromptsPerformBulkActionRequestBody, -} from '@kbn/elastic-assistant-common/impl/schemas/prompts/bulk_crud_prompts_route.gen'; -import { Conversation, ConversationsBulkActions, useAssistantContext } from '../../../../..'; + Conversation, + mergeBaseWithPersistedConversations, + useAssistantContext, + useFetchCurrentUserConversations, +} from '../../../../..'; import { SYSTEM_PROMPT_TABLE_SESSION_STORAGE_KEY } from '../../../../assistant_context/constants'; import { AIConnector } from '../../../../connectorland/connector_selector'; +import { FetchConversationsResponse, useFetchPrompts } from '../../../api'; import { Flyout } from '../../../common/components/assistant_settings_management/flyout'; import { useFlyoutModalVisibility } from '../../../common/components/assistant_settings_management/flyout/use_flyout_modal_visibility'; import { DEFAULT_TABLE_OPTIONS, useSessionPagination, } from '../../../common/components/assistant_settings_management/pagination/use_session_pagination'; -import { CANCEL, DELETE } from '../../../settings/translations'; +import { CANCEL, DELETE, SETTINGS_UPDATED_TOAST_TITLE } from '../../../settings/translations'; +import { useSettingsUpdater } from '../../../settings/use_settings_updater/use_settings_updater'; import { SystemPromptEditor } from '../system_prompt_modal/system_prompt_editor'; import { SETTINGS_TITLE } from '../system_prompt_modal/translations'; import { useSystemPromptEditor } from '../system_prompt_modal/use_system_prompt_editor'; @@ -38,42 +43,42 @@ import { useSystemPromptTable } from './use_system_prompt_table'; interface Props { connectors: AIConnector[] | undefined; - conversationSettings: Record; - conversationsSettingsBulkActions: ConversationsBulkActions; - onSelectedSystemPromptChange: (systemPrompt?: PromptResponse) => void; - selectedSystemPrompt: PromptResponse | undefined; - setUpdatedSystemPromptSettings: React.Dispatch>; - setConversationSettings: React.Dispatch>>; - systemPromptSettings: PromptResponse[]; - setConversationsSettingsBulkActions: React.Dispatch< - React.SetStateAction - >; defaultConnector?: AIConnector; - handleSave: (shouldRefetchConversation?: boolean) => void; - onCancelClick: () => void; - resetSettings: () => void; - promptsBulkActions: PromptsPerformBulkActionRequestBody; - setPromptsBulkActions: React.Dispatch>; } -const SystemPromptSettingsManagementComponent = ({ - connectors, - conversationSettings, - onSelectedSystemPromptChange, - setUpdatedSystemPromptSettings, - setConversationSettings, - selectedSystemPrompt, - systemPromptSettings, - conversationsSettingsBulkActions, - setConversationsSettingsBulkActions, - defaultConnector, - handleSave, - onCancelClick, - resetSettings, - promptsBulkActions, - setPromptsBulkActions, -}: Props) => { - const { nameSpace } = useAssistantContext(); +const SystemPromptSettingsManagementComponent = ({ connectors, defaultConnector }: Props) => { + const { + nameSpace, + http, + assistantAvailability: { isAssistantEnabled }, + baseConversations, + toasts, + } = useAssistantContext(); + + const onFetchedConversations = useCallback( + (conversationsData: FetchConversationsResponse): Record => + mergeBaseWithPersistedConversations(baseConversations, conversationsData), + [baseConversations] + ); + + const { data: allPrompts, refetch: refetchPrompts, isFetched: promptsLoaded } = useFetchPrompts(); + + const { + data: conversations, + isFetched: conversationsLoaded, + refetch: refetchConversations, + } = useFetchCurrentUserConversations({ + http, + onFetch: onFetchedConversations, + isAssistantEnabled, + }); + + const refetchAll = useCallback(() => { + refetchPrompts(); + refetchConversations(); + }, [refetchPrompts, refetchConversations]); + + const isTableLoading = !conversationsLoaded || !promptsLoaded; const { isFlyoutOpen: editFlyoutVisible, openFlyout, closeFlyout } = useFlyoutModalVisibility(); const { isFlyoutOpen: deleteConfirmModalVisibility, @@ -82,6 +87,48 @@ const SystemPromptSettingsManagementComponent = ({ } = useFlyoutModalVisibility(); const [deletedPrompt, setDeletedPrompt] = useState(); + const { + conversationSettings, + setConversationSettings, + systemPromptSettings, + setUpdatedSystemPromptSettings, + conversationsSettingsBulkActions, + setConversationsSettingsBulkActions, + resetSettings, + saveSettings, + promptsBulkActions, + setPromptsBulkActions, + } = useSettingsUpdater(conversations, allPrompts, conversationsLoaded, promptsLoaded); + + // System Prompt Selection State + const [selectedSystemPrompt, setSelectedSystemPrompt] = useState(); + + const onSelectedSystemPromptChange = useCallback((systemPrompt?: PromptResponse) => { + setSelectedSystemPrompt(systemPrompt); + }, []); + + useEffect(() => { + if (selectedSystemPrompt != null) { + setSelectedSystemPrompt(systemPromptSettings.find((p) => p.id === selectedSystemPrompt.id)); + } + }, [selectedSystemPrompt, systemPromptSettings]); + + const handleSave = useCallback( + async (param?: { callback?: () => void }) => { + await saveSettings(); + toasts?.addSuccess({ + iconType: 'check', + title: SETTINGS_UPDATED_TOAST_TITLE, + }); + param?.callback?.(); + }, + [saveSettings, toasts] + ); + + const onCancelClick = useCallback(() => { + resetSettings(); + }, [resetSettings]); + const onCreate = useCallback(() => { onSelectedSystemPromptChange({ id: '', @@ -124,9 +171,9 @@ const SystemPromptSettingsManagementComponent = ({ const onDeleteConfirmed = useCallback(() => { closeConfirmModal(); - handleSave(true); + handleSave({ callback: refetchAll }); setConversationsSettingsBulkActions({}); - }, [closeConfirmModal, handleSave, setConversationsSettingsBulkActions]); + }, [closeConfirmModal, handleSave, refetchAll, setConversationsSettingsBulkActions]); const onSaveCancelled = useCallback(() => { closeFlyout(); @@ -135,9 +182,9 @@ const SystemPromptSettingsManagementComponent = ({ const onSaveConfirmed = useCallback(() => { closeFlyout(); - handleSave(true); + handleSave({ callback: refetchAll }); setConversationsSettingsBulkActions({}); - }, [closeFlyout, handleSave, setConversationsSettingsBulkActions]); + }, [closeFlyout, handleSave, refetchAll, setConversationsSettingsBulkActions]); const confirmationTitle = useMemo( () => @@ -156,8 +203,9 @@ const SystemPromptSettingsManagementComponent = ({ }); const columns = useMemo( - () => getColumns({ onEditActionClicked, onDeleteActionClicked }), - [getColumns, onEditActionClicked, onDeleteActionClicked] + () => + getColumns({ isActionsDisabled: isTableLoading, onEditActionClicked, onDeleteActionClicked }), + [getColumns, isTableLoading, onEditActionClicked, onDeleteActionClicked] ); const systemPromptListItems = useMemo( () => @@ -173,10 +221,13 @@ const SystemPromptSettingsManagementComponent = ({ return ( <> - + + + {i18n.SYSTEM_PROMPTS_TABLE_SETTINGS_DESCRIPTION} + - - {SETTINGS_TITLE} + + {i18n.CREATE_SYSTEM_PROMPT_LABEL} @@ -196,6 +247,7 @@ const SystemPromptSettingsManagementComponent = ({ onClose={onSaveCancelled} onSaveCancelled={onSaveCancelled} onSaveConfirmed={onSaveConfirmed} + saveButtonDisabled={selectedSystemPrompt?.name == null || selectedSystemPrompt?.name === ''} > i18n.translate( 'xpack.elasticAssistant.assistant.promptEditor.modal.deleteSystemPromptConfirmationTitle', @@ -56,3 +64,10 @@ export const DELETE_SYSTEM_PROMPT_MODAL_DESCRIPTION = i18n.translate( defaultMessage: 'You cannot recover the prompt once deleted', } ); + +export const CREATE_SYSTEM_PROMPT_LABEL = i18n.translate( + 'xpack.elasticAssistant.assistant.promptEditor.createSystemPromptLabel', + { + defaultMessage: 'System Prompt', + } +); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/use_system_prompt_table.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/use_system_prompt_table.test.tsx index 48d3232f0ae38..e677001e2d38b 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/use_system_prompt_table.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/use_system_prompt_table.test.tsx @@ -65,14 +65,16 @@ describe('useSystemPromptTable', () => { const onEditActionClicked = jest.fn(); const onDeleteActionClicked = jest.fn(); const columns = result.current.getColumns({ + isActionsDisabled: false, onEditActionClicked, onDeleteActionClicked, }); - expect(columns).toHaveLength(3); + expect(columns).toHaveLength(4); expect(columns[0].name).toBe('Name'); expect(columns[1].name).toBe('Default conversations'); - expect(columns[2].name).toBe('Actions'); + expect(columns[2].name).toBe('Date updated'); + expect(columns[3].name).toBe('Actions'); }); }); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/use_system_prompt_table.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/use_system_prompt_table.tsx index 46e082b86f2c0..d2b63e9abdbd5 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/use_system_prompt_table.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/use_system_prompt_table.tsx @@ -4,34 +4,31 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { EuiBasicTableColumn, EuiIcon, EuiLink } from '@elastic/eui'; +import { EuiBadge, EuiBasicTableColumn, EuiIcon, EuiLink } from '@elastic/eui'; import React, { useCallback } from 'react'; +import { FormattedDate } from '@kbn/i18n-react'; + import { PromptResponse } from '@kbn/elastic-assistant-common'; import { Conversation } from '../../../../assistant_context/types'; import { AIConnector } from '../../../../connectorland/connector_selector'; import { BadgesColumn } from '../../../common/components/assistant_settings_management/badges'; -import { RowActions } from '../../../common/components/assistant_settings_management/row_actions'; -import { - getConversationApiConfig, - getInitialDefaultSystemPrompt, -} from '../../../use_conversation/helpers'; +import { useInlineActions } from '../../../common/components/assistant_settings_management/inline_actions'; +import { getConversationApiConfig } from '../../../use_conversation/helpers'; import { SYSTEM_PROMPT_DEFAULT_NEW_CONVERSATION } from '../system_prompt_modal/translations'; import * as i18n from './translations'; import { getSelectedConversations } from './utils'; -type ConversationsWithSystemPrompt = Record< - string, - Conversation & { systemPrompt: PromptResponse | undefined } ->; - type SystemPromptTableItem = PromptResponse & { defaultConversations: string[] }; export const useSystemPromptTable = () => { + const getActions = useInlineActions(); const getColumns = useCallback( ({ + isActionsDisabled, onEditActionClicked, onDeleteActionClicked, }: { + isActionsDisabled: boolean; onEditActionClicked: (prompt: SystemPromptTableItem) => void; onDeleteActionClicked: (prompt: SystemPromptTableItem) => void; }): Array> => [ @@ -41,7 +38,7 @@ export const useSystemPromptTable = () => { truncateText: { lines: 3 }, render: (prompt: SystemPromptTableItem) => prompt?.name ? ( - onEditActionClicked(prompt)}> + onEditActionClicked(prompt)} disabled={isActionsDisabled}> {prompt?.name} {prompt.isNewConversationDefault && ( { ), }, - /* TODO: enable when createdAt is added { align: 'left', - field: 'createdAt', - name: i18n.SYSTEM_PROMPTS_TABLE_COLUMN_CREATED_ON, + field: 'updatedAt', + name: i18n.SYSTEM_PROMPTS_TABLE_COLUMN_DATE_UPDATED, + render: (updatedAt: SystemPromptTableItem['updatedAt']) => + updatedAt ? ( + + + + ) : null, + sortable: true, }, - */ { align: 'center', - name: 'Actions', width: '120px', - render: (prompt: SystemPromptTableItem) => { - const isDeletable = !prompt.isDefault; - return ( - - rowItem={prompt} - onEdit={onEditActionClicked} - onDelete={isDeletable ? onDeleteActionClicked : undefined} - isDeletable={isDeletable} - /> - ); - }, + ...getActions({ + onDelete: onDeleteActionClicked, + onEdit: onEditActionClicked, + }), }, ], - [] + [getActions] ); const getSystemPromptsList = ({ @@ -99,14 +98,9 @@ export const useSystemPromptTable = () => { defaultConnector: AIConnector | undefined; systemPromptSettings: PromptResponse[]; }): SystemPromptTableItem[] => { - const conversationsWithApiConfig = Object.entries( - conversationSettings - ).reduce((acc, [key, conversation]) => { - const defaultSystemPrompt = getInitialDefaultSystemPrompt({ - allSystemPrompts: systemPromptSettings, - conversation, - }); - + const conversationsWithApiConfig = Object.entries(conversationSettings).reduce< + Record + >((acc, [key, conversation]) => { acc[key] = { ...conversation, ...getConversationApiConfig({ @@ -115,18 +109,19 @@ export const useSystemPromptTable = () => { conversation, defaultConnector, }), - systemPrompt: defaultSystemPrompt, }; + return acc; }, {}); return systemPromptSettings.map((systemPrompt) => { + const defaultConversations = getSelectedConversations( + conversationsWithApiConfig, + systemPrompt?.id + ).map(({ title }) => title); + return { ...systemPrompt, - defaultConversations: getSelectedConversations( - systemPromptSettings, - conversationsWithApiConfig, - systemPrompt?.id - ).map(({ title }) => title), + defaultConversations, }; }); }; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/utils.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/utils.test.tsx index 9fbfb3a8782e0..4ea3943598501 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/utils.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/utils.test.tsx @@ -5,11 +5,9 @@ * 2.0. */ import { ProviderEnum } from '@kbn/elastic-assistant-common'; -import { mockSystemPrompts } from '../../../../mock/system_prompt'; import { getSelectedConversations } from './utils'; import { PromptTypeEnum } from '@kbn/elastic-assistant-common/impl/schemas/prompts/bulk_crud_prompts_route.gen'; describe('getSelectedConversations', () => { - const allSystemPrompts = [...mockSystemPrompts]; const conversationSettings = { '8f1e3218-0b02-480a-8791-78c1ed5f3708': { timestamp: '2024-06-25T12:33:26.779Z', @@ -48,22 +46,14 @@ describe('getSelectedConversations', () => { test('should return selected conversations', () => { const systemPromptId = 'mock-system-prompt-1'; - const conversations = getSelectedConversations( - allSystemPrompts, - conversationSettings, - systemPromptId - ); + const conversations = getSelectedConversations(conversationSettings, systemPromptId); expect(conversations).toEqual(Object.values(conversationSettings)); }); test('should return empty array if no conversations are selected', () => { const systemPromptId = 'ooo'; - const conversations = getSelectedConversations( - allSystemPrompts, - conversationSettings, - systemPromptId - ); + const conversations = getSelectedConversations(conversationSettings, systemPromptId); expect(conversations).toEqual([]); }); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/utils.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/utils.tsx index fd01b8eb318a6..895e175814d91 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/utils.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/utils.tsx @@ -5,18 +5,13 @@ * 2.0. */ -import { PromptResponse } from '@kbn/elastic-assistant-common'; import { Conversation } from '../../../../assistant_context/types'; export const getSelectedConversations = ( - allSystemPrompts: PromptResponse[], conversationSettings: Record, systemPromptId: string ) => { - return Object.values(conversationSettings).filter((conversation) => { - const conversationSystemPrompt = allSystemPrompts.find( - (prompt) => prompt.id === conversation?.apiConfig?.defaultSystemPromptId - ); - return conversationSystemPrompt?.id === systemPromptId; - }); + return Object.values(conversationSettings).filter( + (conversation) => conversation?.apiConfig?.defaultSystemPromptId === systemPromptId + ); }; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings/translations.ts index dd134dc034574..50646560bf489 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings/translations.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings/translations.ts @@ -67,7 +67,7 @@ export const QUICK_PROMPT_CONTEXTS_HELP_TEXT = i18n.translate( 'xpack.elasticAssistant.assistant.quickPrompts.settings.contextsHelpText', { defaultMessage: - 'Select the Prompt Contexts that this Quick Prompt will be available for. Selecting none will make this Quick Prompt available at all times.', + 'Select where this Quick Prompt will appear. Selecting none will make this prompt appear everywhere.', } ); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management/index.tsx index ac93161d35c17..0f7b6df8d1893 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management/index.tsx @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useCallback, useMemo, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { EuiButton, EuiConfirmModal, @@ -13,16 +13,14 @@ import { EuiInMemoryTable, EuiPanel, EuiSpacer, + EuiText, } from '@elastic/eui'; -import { - PromptResponse, - PerformBulkActionRequestBody as PromptsPerformBulkActionRequestBody, -} from '@kbn/elastic-assistant-common/impl/schemas/prompts/bulk_crud_prompts_route.gen'; +import { PromptResponse } from '@kbn/elastic-assistant-common/impl/schemas/prompts/bulk_crud_prompts_route.gen'; import { QuickPromptSettingsEditor } from '../quick_prompt_settings/quick_prompt_editor'; import * as i18n from './translations'; import { useFlyoutModalVisibility } from '../../common/components/assistant_settings_management/flyout/use_flyout_modal_visibility'; import { Flyout } from '../../common/components/assistant_settings_management/flyout'; -import { CANCEL, DELETE } from '../../settings/translations'; +import { CANCEL, DELETE, SETTINGS_UPDATED_TOAST_TITLE } from '../../settings/translations'; import { useQuickPromptEditor } from '../quick_prompt_settings/use_quick_prompt_editor'; import { useQuickPromptTable } from './use_quick_prompt_table'; import { @@ -31,31 +29,58 @@ import { } from '../../common/components/assistant_settings_management/pagination/use_session_pagination'; import { QUICK_PROMPT_TABLE_SESSION_STORAGE_KEY } from '../../../assistant_context/constants'; import { useAssistantContext } from '../../../assistant_context'; +import { + DEFAULT_CONVERSATIONS, + useSettingsUpdater, +} from '../../settings/use_settings_updater/use_settings_updater'; +import { useFetchPrompts } from '../../api'; -interface Props { - handleSave: (shouldRefetchConversation?: boolean) => void; - onCancelClick: () => void; - onSelectedQuickPromptChange: (quickPrompt?: PromptResponse) => void; - quickPromptSettings: PromptResponse[]; - resetSettings?: () => void; - selectedQuickPrompt: PromptResponse | undefined; - setUpdatedQuickPromptSettings: React.Dispatch>; - promptsBulkActions: PromptsPerformBulkActionRequestBody; - setPromptsBulkActions: React.Dispatch>; -} - -const QuickPromptSettingsManagementComponent = ({ - handleSave, - onCancelClick, - onSelectedQuickPromptChange, - quickPromptSettings, - resetSettings, - selectedQuickPrompt, - setUpdatedQuickPromptSettings, - promptsBulkActions, - setPromptsBulkActions, -}: Props) => { - const { nameSpace, basePromptContexts } = useAssistantContext(); +const QuickPromptSettingsManagementComponent = () => { + const { nameSpace, basePromptContexts, toasts } = useAssistantContext(); + + const { data: allPrompts, isFetched: promptsLoaded, refetch: refetchPrompts } = useFetchPrompts(); + + const { + promptsBulkActions, + quickPromptSettings, + resetSettings, + saveSettings, + setPromptsBulkActions, + setUpdatedQuickPromptSettings, + } = useSettingsUpdater( + DEFAULT_CONVERSATIONS, // Quick Prompt settings do not require conversations + allPrompts, + false, // Quick Prompt settings do not require conversations + promptsLoaded + ); + + // Quick Prompt Selection State + const [selectedQuickPrompt, setSelectedQuickPrompt] = useState(); + const onSelectedQuickPromptChange = useCallback((quickPrompt?: PromptResponse) => { + setSelectedQuickPrompt(quickPrompt); + }, []); + + useEffect(() => { + if (selectedQuickPrompt != null) { + setSelectedQuickPrompt(quickPromptSettings.find((q) => q.name === selectedQuickPrompt.name)); + } + }, [quickPromptSettings, selectedQuickPrompt]); + + const handleSave = useCallback( + async (param?: { callback?: () => void }) => { + await saveSettings(); + toasts?.addSuccess({ + iconType: 'check', + title: SETTINGS_UPDATED_TOAST_TITLE, + }); + param?.callback?.(); + }, + [saveSettings, toasts] + ); + + const onCancelClick = useCallback(() => { + resetSettings(); + }, [resetSettings]); const { isFlyoutOpen: editFlyoutVisible, openFlyout, closeFlyout } = useFlyoutModalVisibility(); const [deletedQuickPrompt, setDeletedQuickPrompt] = useState(); @@ -96,9 +121,9 @@ const QuickPromptSettingsManagementComponent = ({ }, [closeConfirmModal, onCancelClick]); const onDeleteConfirmed = useCallback(() => { - handleSave(); + handleSave({ callback: refetchPrompts }); closeConfirmModal(); - }, [closeConfirmModal, handleSave]); + }, [closeConfirmModal, handleSave, refetchPrompts]); const onCreate = useCallback(() => { onSelectedQuickPromptChange(); @@ -112,13 +137,14 @@ const QuickPromptSettingsManagementComponent = ({ }, [closeFlyout, onSelectedQuickPromptChange, onCancelClick]); const onSaveConfirmed = useCallback(() => { - handleSave(); + handleSave({ callback: refetchPrompts }); onSelectedQuickPromptChange(); closeFlyout(); - }, [closeFlyout, handleSave, onSelectedQuickPromptChange]); + }, [closeFlyout, handleSave, onSelectedQuickPromptChange, refetchPrompts]); const { getColumns } = useQuickPromptTable(); const columns = getColumns({ + isActionsDisabled: !promptsLoaded, basePromptContexts, onEditActionClicked, onDeleteActionClicked, @@ -141,9 +167,12 @@ const QuickPromptSettingsManagementComponent = ({ return ( <> - + + + {i18n.QUICK_PROMPTS_DESCRIPTION} + - + {i18n.QUICK_PROMPTS_TABLE_CREATE_BUTTON_TITLE} @@ -163,6 +192,7 @@ const QuickPromptSettingsManagementComponent = ({ onClose={onSaveCancelled} onSaveCancelled={onSaveCancelled} onSaveConfirmed={onSaveConfirmed} + saveButtonDisabled={selectedQuickPrompt?.name == null || selectedQuickPrompt?.name === ''} > { const { result } = renderHook(() => useQuickPromptTable()); + const props = { + isActionsDisabled: false, + basePromptContexts: mockPromptContexts, + onEditActionClicked: mockOnEditActionClicked, + onDeleteActionClicked: mockOnDeleteActionClicked, + }; describe('getColumns', () => { beforeEach(() => { jest.clearAllMocks(); }); it('should return columns with correct render functions', () => { - const columns = result.current.getColumns({ - basePromptContexts: mockPromptContexts, - onEditActionClicked: mockOnEditActionClicked, - onDeleteActionClicked: mockOnDeleteActionClicked, - }); + const columns = result.current.getColumns(props); - expect(columns).toHaveLength(3); + expect(columns).toHaveLength(4); expect(columns[0].name).toBe('Name'); expect(columns[1].name).toBe('Contexts'); - expect(columns[2].name).toBe('Actions'); + expect(columns[2].name).toBe('Date updated'); + expect(columns[3].name).toBe('Actions'); }); it('should render contexts column correctly', () => { - const columns = result.current.getColumns({ - basePromptContexts: mockPromptContexts, - onEditActionClicked: mockOnEditActionClicked, - onDeleteActionClicked: mockOnDeleteActionClicked, - }); + const columns = result.current.getColumns(props); const mockQuickPrompt = { ...MOCK_QUICK_PROMPTS[0], categories: ['alert'] }; const mockBadgesColumn = (columns[1] as EuiTableComputedColumnType).render( @@ -56,42 +55,22 @@ describe('useQuickPromptTable', () => { }); it('should not render delete action for non-deletable prompt', () => { - const columns = result.current.getColumns({ - basePromptContexts: mockPromptContexts, - onEditActionClicked: mockOnEditActionClicked, - onDeleteActionClicked: mockOnDeleteActionClicked, - }); - - const mockRowActions = (columns[2] as EuiTableComputedColumnType).render( - MOCK_QUICK_PROMPTS[0] - ); + const columns = result.current.getColumns(props); - expect(mockRowActions).toHaveProperty('props', { - rowItem: MOCK_QUICK_PROMPTS[0], - onDelete: undefined, - onEdit: mockOnEditActionClicked, - isDeletable: false, - }); + const defaultPrompt = MOCK_QUICK_PROMPTS.find((qp) => qp.isDefault); + if (defaultPrompt) { + const mockRowActions = (columns[3] as EuiTableActionsColumnType).actions[1]; + expect(mockRowActions?.enabled?.(defaultPrompt)).toEqual(false); + } }); it('should render delete actions correctly for deletable prompt', () => { - const columns = result.current.getColumns({ - basePromptContexts: mockPromptContexts, - onEditActionClicked: mockOnEditActionClicked, - onDeleteActionClicked: mockOnDeleteActionClicked, - }); + const columns = result.current.getColumns(props); const nonDefaultPrompt = MOCK_QUICK_PROMPTS.find((qp) => !qp.isDefault); if (nonDefaultPrompt) { - const mockRowActions = (columns[2] as EuiTableComputedColumnType).render( - nonDefaultPrompt - ); - expect(mockRowActions).toHaveProperty('props', { - rowItem: nonDefaultPrompt, - onDelete: mockOnDeleteActionClicked, - onEdit: mockOnEditActionClicked, - isDeletable: true, - }); + const mockRowActions = (columns[3] as EuiTableActionsColumnType).actions[1]; + expect(mockRowActions?.enabled?.(nonDefaultPrompt)).toEqual(true); } }); }); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management/use_quick_prompt_table.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management/use_quick_prompt_table.tsx index 1899905db0ea1..7c6a250224184 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management/use_quick_prompt_table.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management/use_quick_prompt_table.tsx @@ -5,21 +5,25 @@ * 2.0. */ -import { EuiBasicTableColumn, EuiLink } from '@elastic/eui'; +import { EuiBadge, EuiBasicTableColumn, EuiLink } from '@elastic/eui'; import React, { useCallback } from 'react'; import { PromptResponse } from '@kbn/elastic-assistant-common'; +import { FormattedDate } from '@kbn/i18n-react'; import { BadgesColumn } from '../../common/components/assistant_settings_management/badges'; -import { RowActions } from '../../common/components/assistant_settings_management/row_actions'; import { PromptContextTemplate } from '../../prompt_context/types'; import * as i18n from './translations'; +import { useInlineActions } from '../../common/components/assistant_settings_management/inline_actions'; export const useQuickPromptTable = () => { + const getActions = useInlineActions(); const getColumns = useCallback( ({ + isActionsDisabled, basePromptContexts, onEditActionClicked, onDeleteActionClicked, }: { + isActionsDisabled: boolean; basePromptContexts: PromptContextTemplate[]; onEditActionClicked: (prompt: PromptResponse) => void; onDeleteActionClicked: (prompt: PromptResponse) => void; @@ -29,7 +33,9 @@ export const useQuickPromptTable = () => { name: i18n.QUICK_PROMPTS_TABLE_COLUMN_NAME, render: (prompt: PromptResponse) => prompt?.name ? ( - onEditActionClicked(prompt)}>{prompt?.name} + onEditActionClicked(prompt)} disabled={isActionsDisabled}> + {prompt?.name} + ) : null, sortable: ({ name }: PromptResponse) => name, }, @@ -47,34 +53,33 @@ export const useQuickPromptTable = () => { ) : null; }, }, - /* TODO: enable when createdAt is added { align: 'left', - field: 'createdAt', - name: i18n.QUICK_PROMPTS_TABLE_COLUMN_CREATED_AT, + field: 'updatedAt', + name: i18n.QUICK_PROMPTS_TABLE_COLUMN_DATE_UPDATED, + render: (updatedAt: PromptResponse['updatedAt']) => + updatedAt ? ( + + + + ) : null, + sortable: true, }, - */ { align: 'center', - name: i18n.QUICK_PROMPTS_TABLE_COLUMN_ACTIONS, width: '120px', - render: (prompt: PromptResponse) => { - if (!prompt) { - return null; - } - const isDeletable = !prompt.isDefault; - return ( - - rowItem={prompt} - onDelete={isDeletable ? onDeleteActionClicked : undefined} - onEdit={onEditActionClicked} - isDeletable={isDeletable} - /> - ); - }, + ...getActions({ + onDelete: onDeleteActionClicked, + onEdit: onEditActionClicked, + }), }, ], - [] + [getActions] ); return { getColumns }; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings.tsx index 4b46d2b75d0a9..692bf9cc7c62d 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings.tsx @@ -81,7 +81,6 @@ export const AssistantSettings: React.FC = React.memo( conversationsLoaded, }) => { const { - actionTypeRegistry, assistantFeatures: { assistantModelEvaluation: modelEvaluatorEnabled }, http, toasts, @@ -97,7 +96,7 @@ export const AssistantSettings: React.FC = React.memo( const { data: anonymizationFields, refetch: refetchAnonymizationFieldsResults } = useFetchAnonymizationFields(); - const { data: allPrompts } = useFetchPrompts(); + const { data: allPrompts, isFetched: promptsLoaded } = useFetchPrompts(); const { data: connectors } = useLoadConnectors({ http, @@ -123,7 +122,13 @@ export const AssistantSettings: React.FC = React.memo( setUpdatedAnonymizationData, setPromptsBulkActions, setUpdatedSystemPromptSettings, - } = useSettingsUpdater(conversations, allPrompts, conversationsLoaded, anonymizationFields); + } = useSettingsUpdater( + conversations, + allPrompts, + conversationsLoaded, + promptsLoaded, + anonymizationFields + ); // Local state for saving previously selected items so tab switching is friendlier // Conversation Selection State @@ -315,14 +320,13 @@ export const AssistantSettings: React.FC = React.memo( className="eui-scrollBar" grow={true} css={css` - max-height: 550px; + max-height: 519px; overflow-y: scroll; `} > {!selectedSettingsTab || (selectedSettingsTab === CONVERSATIONS_TAB && ( void; + onSaveButtonClicked: () => void; +}> = React.memo(({ hasPendingChanges, onCancelClick, onSaveButtonClicked }) => + hasPendingChanges ? ( + + + + + {CANCEL} + + + + + {SAVE} + + + + + ) : null +); +AssistantSettingsBottomBar.displayName = 'AssistantSettingsBottomBar'; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.test.tsx index 7d70ee5ede730..d8e207cbb23cd 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.test.tsx @@ -10,10 +10,11 @@ import { useAssistantContext } from '../../assistant_context'; import { fireEvent, render } from '@testing-library/react'; import React from 'react'; -import { OpenAiProviderType } from '@kbn/stack-connectors-plugin/common/openai/constants'; +import { I18nProvider } from '@kbn/i18n-react'; import { MOCK_QUICK_PROMPTS } from '../../mock/quick_prompt'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { AssistantSettingsManagement } from './assistant_settings_management'; + import { ANONYMIZATION_TAB, CONNECTORS_TAB, @@ -51,22 +52,9 @@ const mockContext = { isAssistantEnabled: true, }, }; -const onClose = jest.fn(); -const onSave = jest.fn().mockResolvedValue(() => {}); -const onConversationSelected = jest.fn(); const testProps = { - conversationsLoaded: true, - defaultConnectorId: '123', - defaultProvider: OpenAiProviderType.OpenAi, selectedConversation: welcomeConvo, - onClose, - onSave, - onConversationSelected, - conversations: {}, - anonymizationFields: { total: 0, page: 1, perPage: 1000, data: [] }, - refetchAnonymizationFieldsResults: jest.fn(), - refetchConversations: jest.fn(), }; jest.mock('../../assistant_context'); @@ -86,6 +74,10 @@ jest.mock('../prompt_editor/system_prompt/system_prompt_settings_management', () SystemPromptSettingsManagement: () => , })); +jest.mock('../../knowledge_base/knowledge_base_settings_management', () => ({ + KnowledgeBaseSettingsManagement: () => , +})); + jest.mock('../../data_anonymization/settings/anonymization_settings_management', () => ({ AnonymizationSettingsManagement: () => , })); @@ -93,7 +85,6 @@ jest.mock('../../data_anonymization/settings/anonymization_settings_management', jest.mock('.', () => { return { EvaluationSettings: () => , - KnowledgeBaseSettings: () => , }; }); @@ -105,10 +96,16 @@ jest.mock('./use_settings_updater/use_settings_updater', () => { }; }); +jest.mock('../../connectorland/use_load_connectors', () => ({ + useLoadConnectors: jest.fn().mockReturnValue({ data: [] }), +})); + const queryClient = new QueryClient(); const wrapper = (props: { children: React.ReactNode }) => ( - {props.children} + + {props.children} + ); describe('AssistantSettingsManagement', () => { diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx index be6370d36e841..89c00fbf88773 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx @@ -5,29 +5,15 @@ * 2.0. */ -import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import { - EuiAvatar, - EuiButton, - EuiButtonEmpty, - EuiFlexGroup, - EuiFlexItem, - EuiPageTemplate, - EuiTitle, - useEuiShadow, - useEuiTheme, -} from '@elastic/eui'; +import React, { useEffect, useMemo } from 'react'; +import { EuiAvatar, EuiPageTemplate, EuiTitle, useEuiShadow, useEuiTheme } from '@elastic/eui'; import { css } from '@emotion/react'; -import { PromptResponse, PromptTypeEnum } from '@kbn/elastic-assistant-common'; import { Conversation } from '../../..'; import * as i18n from './translations'; import { useAssistantContext } from '../../assistant_context'; -import { useSettingsUpdater } from './use_settings_updater/use_settings_updater'; -import { KnowledgeBaseSettings, EvaluationSettings } from '.'; import { useLoadConnectors } from '../../connectorland/use_load_connectors'; import { getDefaultConnector } from '../helpers'; -import { useFetchAnonymizationFields } from '../api/anonymization_fields/use_fetch_anonymization_fields'; import { ConnectorsSettingsManagement } from '../../connectorland/connector_settings_management'; import { ConversationSettingsManagement } from '../conversations/conversation_settings_management'; import { QuickPromptSettingsManagement } from '../quick_prompts/quick_prompt_settings_management'; @@ -43,13 +29,11 @@ import { QUICK_PROMPTS_TAB, SYSTEM_PROMPTS_TAB, } from './const'; -import { useFetchPrompts } from '../api/prompts/use_fetch_prompts'; +import { KnowledgeBaseSettingsManagement } from '../../knowledge_base/knowledge_base_settings_management'; +import { EvaluationSettings } from '.'; interface Props { - conversations: Record; - conversationsLoaded: boolean; selectedConversation: Conversation; - refetchConversations: () => void; } /** @@ -57,149 +41,28 @@ interface Props { * anonymization, knowledge base, and evaluation via the `isModelEvaluationEnabled` feature flag. */ export const AssistantSettingsManagement: React.FC = React.memo( - ({ - conversations, - conversationsLoaded, - refetchConversations, - selectedConversation: defaultSelectedConversation, - }) => { + ({ selectedConversation: defaultSelectedConversation }) => { const { assistantFeatures: { assistantModelEvaluation: modelEvaluatorEnabled }, http, selectedSettingsTab, setSelectedSettingsTab, - toasts, } = useAssistantContext(); - const { data: anonymizationFields } = useFetchAnonymizationFields(); - - const { data: allPrompts } = useFetchPrompts(); - - // Connector details const { data: connectors } = useLoadConnectors({ http, }); const defaultConnector = useMemo(() => getDefaultConnector(connectors), [connectors]); - const [hasPendingChanges, setHasPendingChanges] = useState(false); const { euiTheme } = useEuiTheme(); const headerIconShadow = useEuiShadow('s'); - const { - conversationSettings, - setConversationSettings, - knowledgeBase, - quickPromptSettings, - systemPromptSettings, - assistantStreamingEnabled, - setUpdatedAssistantStreamingEnabled, - setUpdatedKnowledgeBaseSettings, - setUpdatedQuickPromptSettings, - setPromptsBulkActions, - saveSettings, - conversationsSettingsBulkActions, - updatedAnonymizationData, - setConversationsSettingsBulkActions, - anonymizationFieldsBulkActions, - setAnonymizationFieldsBulkActions, - setUpdatedAnonymizationData, - setUpdatedSystemPromptSettings, - promptsBulkActions, - resetSettings, - } = useSettingsUpdater( - conversations, - allPrompts, - conversationsLoaded, - anonymizationFields ?? { page: 0, perPage: 0, total: 0, data: [] } - ); - - const quickPrompts = useMemo( - () => - quickPromptSettings.length === 0 - ? allPrompts.data.filter((p) => p.promptType === PromptTypeEnum.quick) - : quickPromptSettings, - [allPrompts.data, quickPromptSettings] - ); - - const systemPrompts = useMemo( - () => - systemPromptSettings.length === 0 - ? allPrompts.data.filter((p) => p.promptType === PromptTypeEnum.system) - : systemPromptSettings, - [allPrompts.data, systemPromptSettings] - ); - - // Local state for saving previously selected items so tab switching is friendlier - // Conversation Selection State - const [selectedConversation, setSelectedConversation] = useState( - () => { - return conversationSettings[defaultSelectedConversation.title]; - } - ); - - const onHandleSelectedConversationChange = useCallback((conversation?: Conversation) => { - setSelectedConversation(conversation); - }, []); - - useEffect(() => { - if (selectedConversation != null) { - setSelectedConversation( - // conversationSettings has title as key, sometime has id as key - conversationSettings[selectedConversation.id] || - conversationSettings[selectedConversation.title] - ); - } - }, [conversationSettings, selectedConversation]); - useEffect(() => { if (selectedSettingsTab == null) { setSelectedSettingsTab(CONNECTORS_TAB); } }, [selectedSettingsTab, setSelectedSettingsTab]); - // Quick Prompt Selection State - const [selectedQuickPrompt, setSelectedQuickPrompt] = useState(); - const onHandleSelectedQuickPromptChange = useCallback((quickPrompt?: PromptResponse) => { - setSelectedQuickPrompt(quickPrompt); - }, []); - useEffect(() => { - if (selectedQuickPrompt != null) { - setSelectedQuickPrompt( - quickPromptSettings.find((q) => q.name === selectedQuickPrompt.name) - ); - } - }, [quickPromptSettings, selectedQuickPrompt]); - - // System Prompt Selection State - const [selectedSystemPrompt, setSelectedSystemPrompt] = useState(); - const onHandleSelectedSystemPromptChange = useCallback((systemPrompt?: PromptResponse) => { - setSelectedSystemPrompt(systemPrompt); - }, []); - useEffect(() => { - if (selectedSystemPrompt != null) { - setSelectedSystemPrompt(systemPromptSettings.find((p) => p.id === selectedSystemPrompt.id)); - } - }, [selectedSystemPrompt, systemPromptSettings]); - - const handleSave = useCallback( - async (shouldRefetchConversation?: boolean) => { - await saveSettings(); - toasts?.addSuccess({ - iconType: 'check', - title: i18n.SETTINGS_UPDATED_TOAST_TITLE, - }); - setHasPendingChanges(false); - if (shouldRefetchConversation) { - refetchConversations(); - } - }, - [refetchConversations, saveSettings, toasts] - ); - - const onSaveButtonClicked = useCallback(() => { - handleSave(true); - }, [handleSave]); - const tabsConfig = useMemo( () => [ { @@ -247,18 +110,6 @@ export const AssistantSettingsManagement: React.FC = React.memo( })); }, [setSelectedSettingsTab, selectedSettingsTab, tabsConfig]); - const handleChange = useCallback( - (callback) => (value: unknown) => { - setHasPendingChanges(true); - callback(value); - }, - [] - ); - - const onCancelClick = useCallback(() => { - resetSettings(); - setHasPendingChanges(false); - }, [resetSettings]); return ( <> = React.memo( `} /> -

{i18n.SECURITY_AI_SETTINGS}

+ {i18n.SECURITY_AI_SETTINGS}
} @@ -294,100 +145,22 @@ export const AssistantSettingsManagement: React.FC = React.memo( {selectedSettingsTab === CONNECTORS_TAB && } {selectedSettingsTab === CONVERSATIONS_TAB && ( )} {selectedSettingsTab === SYSTEM_PROMPTS_TAB && ( - )} - {selectedSettingsTab === QUICK_PROMPTS_TAB && ( - - )} - {selectedSettingsTab === ANONYMIZATION_TAB && ( - - )} - {selectedSettingsTab === KNOWLEDGE_BASE_TAB && ( - )} + {selectedSettingsTab === QUICK_PROMPTS_TAB && } + {selectedSettingsTab === ANONYMIZATION_TAB && } + {selectedSettingsTab === KNOWLEDGE_BASE_TAB && } {selectedSettingsTab === EVALUATION_TAB && } - {hasPendingChanges && ( - - - - - {i18n.CANCEL} - - - - - {i18n.SAVE} - - - - - )} ); } diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/evaluation_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/evaluation_settings.tsx index 71bbab7636a4a..e6ce69f65abab 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/evaluation_settings.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/evaluation_settings.tsx @@ -23,6 +23,7 @@ import { EuiFlexItem, EuiFlexGroup, EuiLink, + EuiPanel, } from '@elastic/eui'; import { css } from '@emotion/react'; @@ -348,12 +349,8 @@ export const EvaluationSettings: React.FC = React.memo(() => { `; return ( - <> - -

{i18n.SETTINGS_TITLE}

-
- - {i18n.SETTINGS_DESCRIPTION} + + {i18n.SETTINGS_DESCRIPTION} {/* Run Details*/} { { - + ); }); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/translations.ts index 517f4456b49e8..e875b4c35b203 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/translations.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/translations.ts @@ -31,7 +31,7 @@ export const RUN_DETAILS_TITLE = i18n.translate( export const RUN_DETAILS_DESCRIPTION = i18n.translate( 'xpack.elasticAssistant.assistant.settings.evaluationSettings.runDetailsDescription', { - defaultMessage: 'Configure test run details like project, run name, dataset, and output index', + defaultMessage: 'Configure test run details like project, run name, dataset, and output index.', } ); @@ -46,7 +46,7 @@ export const PREDICTION_DETAILS_DESCRIPTION = i18n.translate( 'xpack.elasticAssistant.assistant.settings.evaluationSettings.predictionDetailsDescription', { defaultMessage: - 'Choose models (connectors) and corresponding agents the dataset should run against', + 'Choose models (connectors) and corresponding agents the dataset should run against.', } ); @@ -61,7 +61,7 @@ export const EVALUATION_DETAILS_DESCRIPTION = i18n.translate( 'xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluationDetailsDescription', { defaultMessage: - 'Evaluate prediction results using a specific model (connector) and evaluation criterion', + 'Evaluate prediction results using a specific model (connector) and evaluation criterion.', } ); @@ -75,7 +75,7 @@ export const PROJECT_LABEL = i18n.translate( export const PROJECT_DESCRIPTION = i18n.translate( 'xpack.elasticAssistant.assistant.settings.evaluationSettings.projectDescription', { - defaultMessage: 'LangSmith project to write results to', + defaultMessage: 'LangSmith project to write results to.', } ); @@ -96,7 +96,7 @@ export const RUN_NAME_LABEL = i18n.translate( export const RUN_NAME_DESCRIPTION = i18n.translate( 'xpack.elasticAssistant.assistant.settings.evaluationSettings.runNameDescription', { - defaultMessage: 'Name for this specific test run', + defaultMessage: 'Name for this specific test run.', } ); @@ -117,7 +117,7 @@ export const CONNECTORS_LABEL = i18n.translate( export const CONNECTORS_DESCRIPTION = i18n.translate( 'xpack.elasticAssistant.assistant.settings.evaluationSettings.connectorsDescription', { - defaultMessage: 'Select whichever models you want to evaluate the dataset against', + defaultMessage: 'Select models to evaluate the dataset against.', } ); @@ -131,7 +131,7 @@ export const AGENTS_LABEL = i18n.translate( export const AGENTS_DESCRIPTION = i18n.translate( 'xpack.elasticAssistant.assistant.settings.evaluationSettings.agentsDescription', { - defaultMessage: 'Select the agents (i.e. RAG algos) to evaluate the dataset against', + defaultMessage: 'Select the agents (RAG algorithms) to evaluate the dataset against.', } ); @@ -145,7 +145,7 @@ export const EVALUATOR_MODEL_LABEL = i18n.translate( export const EVALUATOR_MODEL_DESCRIPTION = i18n.translate( 'xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluatorModelDescription', { - defaultMessage: 'Model to perform the final evaluation with', + defaultMessage: 'Model that performs the final evaluation.', } ); @@ -160,7 +160,7 @@ export const EVALUATION_TYPE_DESCRIPTION = i18n.translate( 'xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluationTypeDescription', { defaultMessage: - 'Type of evaluation to perform, e.g. "correctness" "esql-validator", or "custom" and provide your own evaluation prompt', + 'Type of evaluation to perform, e.g. "correctness" "esql-validator", or "custom".', } ); @@ -175,7 +175,7 @@ export const EVALUATION_PROMPT_DESCRIPTION = i18n.translate( 'xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluationPromptDescription', { defaultMessage: - 'Prompt template given `input`, `reference` and `prediction` template variables', + 'Prompt template given `input`, `reference` and `prediction` template variables.', } ); export const EVALUATOR_OUTPUT_INDEX_LABEL = i18n.translate( @@ -189,7 +189,7 @@ export const EVALUATOR_OUTPUT_INDEX_DESCRIPTION = i18n.translate( 'xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluatorOutputIndexDescription', { defaultMessage: - 'Index to write results to. Must be prefixed with ".kibana-elastic-ai-assistant-"', + 'Index to write results to. Must be prefixed with ".kibana-elastic-ai-assistant-".', } ); @@ -211,7 +211,7 @@ export const APM_URL_DESCRIPTION = i18n.translate( 'xpack.elasticAssistant.assistant.settings.evaluationSettings.apmUrlDescription', { defaultMessage: - 'URL for the Kibana APM app. Used to link to APM traces for evaluation results. Defaults to "{defaultUrlPath}"', + 'URL for the Kibana APM app. Used to link to APM traces for evaluation results. Defaults to "{defaultUrlPath}".', values: { defaultUrlPath: '${basePath}/app/apm', }, @@ -228,7 +228,7 @@ export const LANGSMITH_PROJECT_LABEL = i18n.translate( export const LANGSMITH_PROJECT_DESCRIPTION = i18n.translate( 'xpack.elasticAssistant.assistant.settings.evaluationSettings.langSmithProjectDescription', { - defaultMessage: 'LangSmith Project to write traces to', + defaultMessage: 'LangSmith Project to write traces to.', } ); @@ -264,7 +264,7 @@ export const LANGSMITH_DATASET_LABEL = i18n.translate( export const LANGSMITH_DATASET_DESCRIPTION = i18n.translate( 'xpack.elasticAssistant.assistant.settings.evaluationSettings.langsmithDatasetDescription', { - defaultMessage: 'Name of dataset hosted on LangSmith to evaluate', + defaultMessage: 'Name of dataset hosted on LangSmith to evaluate.', } ); @@ -286,7 +286,7 @@ export const CUSTOM_DATASET_DESCRIPTION = i18n.translate( 'xpack.elasticAssistant.assistant.settings.evaluationSettings.customDatasetDescription', { defaultMessage: - 'Custom dataset to evaluate. Array of objects with "input" and "references" properties', + 'Custom dataset to evaluate. Array of objects with "input" and "references" properties.', } ); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/use_settings_updater/use_settings_updater.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/use_settings_updater/use_settings_updater.test.tsx index 0a2c72ba80ac4..c7efa1f8e5922 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/use_settings_updater/use_settings_updater.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/use_settings_updater/use_settings_updater.test.tsx @@ -17,7 +17,8 @@ const mockConversations = { [alertConvo.title]: alertConvo, [welcomeConvo.title]: welcomeConvo, }; -const conversationsLoaded = true; +const conversationsLoaded = false; +const promptsLoaded = false; const mockHttp = { fetch: jest.fn(), @@ -112,6 +113,7 @@ describe('useSettingsUpdater', () => { total: 10, }, conversationsLoaded, + promptsLoaded, anonymizationFields ) ); @@ -168,6 +170,7 @@ describe('useSettingsUpdater', () => { total: 10, }, conversationsLoaded, + promptsLoaded, anonymizationFields ) ); @@ -215,6 +218,7 @@ describe('useSettingsUpdater', () => { total: 10, }, conversationsLoaded, + promptsLoaded, anonymizationFields ) ); @@ -242,6 +246,7 @@ describe('useSettingsUpdater', () => { total: 10, }, conversationsLoaded, + promptsLoaded, anonymizationFields ) ); @@ -270,6 +275,7 @@ describe('useSettingsUpdater', () => { total: 10, }, conversationsLoaded, + promptsLoaded, anonymizationFields ) ); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/use_settings_updater/use_settings_updater.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/use_settings_updater/use_settings_updater.tsx index 1ae1c9e5b1b73..f08a6f9fe6866 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/use_settings_updater/use_settings_updater.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/use_settings_updater/use_settings_updater.tsx @@ -24,6 +24,16 @@ import { import { bulkUpdateAnonymizationFields } from '../../api/anonymization_fields/bulk_update_anonymization_fields'; import { bulkUpdatePrompts } from '../../api/prompts/bulk_update_prompts'; +export const DEFAULT_ANONYMIZATION_FIELDS = { + page: 0, + perPage: 0, + total: 0, + data: [], +}; + +export const DEFAULT_CONVERSATIONS: Record = {}; + +export const DEFAULT_PROMPTS: FindPromptsResponse = { page: 0, perPage: 0, total: 0, data: [] }; interface UseSettingsUpdater { assistantStreamingEnabled: boolean; conversationSettings: Record; @@ -57,7 +67,8 @@ export const useSettingsUpdater = ( conversations: Record, allPrompts: FindPromptsResponse, conversationsLoaded: boolean, - anonymizationFields: FindAnonymizationFieldsResponse + promptsLoaded: boolean, + anonymizationFields: FindAnonymizationFieldsResponse = DEFAULT_ANONYMIZATION_FIELDS // Put default as a constant to avoid re-creating it on every render ): UseSettingsUpdater => { // Initial state from assistant context const { @@ -100,7 +111,6 @@ export const useSettingsUpdater = ( // Knowledge Base const [updatedKnowledgeBaseSettings, setUpdatedKnowledgeBaseSettings] = useState(knowledgeBase); - /** * Reset all pending settings */ @@ -115,6 +125,7 @@ export const useSettingsUpdater = ( setUpdatedSystemPromptSettings( allPrompts.data.filter((p) => p.promptType === PromptTypeEnum.system) ); + setPromptsBulkActions({}); setUpdatedAnonymizationData(anonymizationFields); }, [allPrompts, anonymizationFields, assistantStreamingEnabled, conversations, knowledgeBase]); @@ -188,6 +199,8 @@ export const useSettingsUpdater = ( ? await bulkUpdateAnonymizationFields(http, anonymizationFieldsBulkActions, toasts) : undefined; + setPromptsBulkActions({}); + setConversationsSettingsBulkActions({}); return ( (bulkResult?.success ?? true) && (bulkAnonymizationFieldsResult?.success ?? true) && @@ -235,6 +248,18 @@ export const useSettingsUpdater = ( } }, [conversations, conversationsLoaded]); + useEffect(() => { + // Update quick prompts settings when prompts are loaded + if (promptsLoaded) { + setUpdatedQuickPromptSettings( + allPrompts.data.filter((p) => p.promptType === PromptTypeEnum.quick) + ); + setUpdatedSystemPromptSettings( + allPrompts.data.filter((p) => p.promptType === PromptTypeEnum.system) + ); + } + }, [allPrompts.data, promptsLoaded]); + return { conversationSettings, conversationsSettingsBulkActions, diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_conversation/helpers.test.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_conversation/helpers.test.ts index 3e997fef5d573..a5ae389a40353 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_conversation/helpers.test.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_conversation/helpers.test.ts @@ -72,7 +72,7 @@ describe('useConversation helpers', () => { { id: '2', content: 'Prompt 2', - name: 'Prompt 2', + name: 'Default system prompt', promptType: 'quick', isNewConversationDefault: true, }, @@ -99,16 +99,31 @@ describe('useConversation helpers', () => { }); describe('getDefaultNewSystemPrompt', () => { + const systemPrompts: PromptResponse[] = [ + { + id: '1', + content: 'Prompt 1', + name: 'Default system prompt', + promptType: 'system', + }, + { + id: '2', + content: 'Prompt 2', + name: 'Prompt 2', + promptType: 'system', + isNewConversationDefault: true, + }, + ]; test('should return the default (starred) isNewConversationDefault system prompt', () => { - const result = getDefaultNewSystemPrompt(allSystemPrompts); + const result = getDefaultNewSystemPrompt(systemPrompts); - expect(result).toEqual(allSystemPrompts[1]); + expect(result).toEqual(systemPrompts[1]); }); - test('should return the first prompt if default new system prompt do not exist', () => { - const result = getDefaultNewSystemPrompt(allSystemPromptsNoDefault); + test('should return the fallback prompt if default new system prompt do not exist', () => { + const result = getDefaultNewSystemPrompt([systemPrompts[0]]); - expect(result).toEqual(allSystemPromptsNoDefault[0]); + expect(result).toEqual(systemPrompts[0]); }); test('should return undefined if default (starred) isNewConversationDefault system prompt does not exist and there are no system prompts', () => { @@ -131,53 +146,25 @@ describe('useConversation helpers', () => { replacements: {}, title: '1', }; - test('should return the conversation system prompt if it exists', () => { + test('should return the conversation system prompt', () => { const result = getDefaultSystemPrompt({ allSystemPrompts, conversation }); expect(result).toEqual(allSystemPrompts[2]); }); - test('should return the default (starred) isNewConversationDefault system prompt if conversation system prompt does not exist', () => { - const conversationWithoutSystemPrompt: Conversation = { - ...conversation, - apiConfig: { connectorId: '123', actionTypeId: '.gen-ai' }, - }; + test('should return undefined if the conversation system prompt does not exist', () => { const result = getDefaultSystemPrompt({ allSystemPrompts, - conversation: conversationWithoutSystemPrompt, - }); - - expect(result).toEqual(allSystemPrompts[1]); - }); - - test('should return the default (starred) isNewConversationDefault system prompt if conversation system prompt does not exist within all system prompts', () => { - const conversationWithoutSystemPrompt: Conversation = { - apiConfig: { connectorId: '123', actionTypeId: '.gen-ai' }, - replacements: {}, - category: 'assistant', - id: '4', // this id does not exist within allSystemPrompts - messages: [], - title: '4', - }; - const result = getDefaultSystemPrompt({ - allSystemPrompts, - conversation: conversationWithoutSystemPrompt, - }); - - expect(result).toEqual(allSystemPrompts[1]); - }); - - test('should return the first prompt if both conversation system prompt and default new system prompt do not exist', () => { - const conversationWithoutSystemPrompt: Conversation = { - ...conversation, - apiConfig: { connectorId: '123', actionTypeId: '.gen-ai' }, - }; - const result = getDefaultSystemPrompt({ - allSystemPrompts: allSystemPromptsNoDefault, - conversation: conversationWithoutSystemPrompt, + conversation: { + ...conversation, + apiConfig: { + ...conversation.apiConfig, + defaultSystemPromptId: undefined, + }, + } as Conversation, }); - expect(result).toEqual(allSystemPromptsNoDefault[0]); + expect(result).toBeUndefined(); }); test('should return undefined if conversation system prompt does not exist and there are no system prompts', () => { @@ -190,40 +177,21 @@ describe('useConversation helpers', () => { conversation: conversationWithoutSystemPrompt, }); - expect(result).toEqual(undefined); + expect(result).toBeUndefined(); }); test('should return undefined if conversation system prompt does not exist within all system prompts', () => { const conversationWithoutSystemPrompt: Conversation = { ...conversation, - apiConfig: { connectorId: '123', actionTypeId: '.gen-ai' }, - replacements: {}, - id: '4', // this id does not exist within allSystemPrompts + apiConfig: { connectorId: '123', actionTypeId: '.gen-ai', defaultSystemPromptId: 'xxx' }, + id: '4', }; const result = getDefaultSystemPrompt({ allSystemPrompts: allSystemPromptsNoDefault, conversation: conversationWithoutSystemPrompt, }); - expect(result).toEqual(allSystemPromptsNoDefault[0]); - }); - - test('should return (starred) isNewConversationDefault system prompt if conversation is undefined', () => { - const result = getDefaultSystemPrompt({ - allSystemPrompts, - conversation: undefined, - }); - - expect(result).toEqual(allSystemPrompts[1]); - }); - - test('should return the first system prompt if the conversation is undefined and isNewConversationDefault is not present in system prompts', () => { - const result = getDefaultSystemPrompt({ - allSystemPrompts: allSystemPromptsNoDefault, - conversation: undefined, - }); - - expect(result).toEqual(allSystemPromptsNoDefault[0]); + expect(result).toBeUndefined(); }); test('should return undefined if conversation is undefined and no system prompts are provided', () => { @@ -235,242 +203,142 @@ describe('useConversation helpers', () => { expect(result).toEqual(undefined); }); }); -}); - -describe('getConversationApiConfig', () => { - const allSystemPrompts: PromptResponse[] = [ - { - id: '1', - content: 'Prompt 1', - name: 'Prompt 1', - promptType: 'quick', - }, - { - id: '2', - content: 'Prompt 2', - name: 'Prompt 2', - promptType: 'quick', - isNewConversationDefault: true, - }, - { - id: '3', - content: 'Prompt 3', - name: 'Prompt 3', - promptType: 'quick', - }, - ]; - const conversation: Conversation = { - apiConfig: { - connectorId: '123', - actionTypeId: '.gen-ai', - defaultSystemPromptId: '2', - model: 'gpt-3', - }, - category: 'assistant', - id: '1', - messages: [], - replacements: {}, - title: 'Test Conversation', - }; - - const connectors: AIConnector[] = [ - { - id: '123', - actionTypeId: '.gen-ai', - apiProvider: OpenAiProviderType.OpenAi, - }, - { - id: '456', - actionTypeId: '.gen-ai', - apiProvider: OpenAiProviderType.AzureAi, - }, - ] as AIConnector[]; - - const defaultConnector: AIConnector = { - id: '456', - actionTypeId: '.gen-ai', - apiProvider: OpenAiProviderType.AzureAi, - } as AIConnector; - - test('should return the correct API config when connector and system prompt are found', () => { - const result = getConversationApiConfig({ - allSystemPrompts, - conversation, - connectors, - defaultConnector, - }); - - expect(result).toEqual({ + describe('getConversationApiConfig', () => { + const conversation: Conversation = { apiConfig: { connectorId: '123', actionTypeId: '.gen-ai', - provider: OpenAiProviderType.OpenAi, defaultSystemPromptId: '2', model: 'gpt-3', }, - }); - }); - - test('should return the default connector when specific connector is not found', () => { - const conversationWithMissingConnector: Conversation = { - ...conversation, - apiConfig: { ...conversation.apiConfig, connectorId: '999' } as Conversation['apiConfig'], + category: 'assistant', + id: '1', + messages: [], + replacements: {}, + title: 'Test Conversation', }; - const result = getConversationApiConfig({ - allSystemPrompts, - conversation: conversationWithMissingConnector, - connectors, - defaultConnector, - }); - - expect(result).toEqual({ - apiConfig: { - connectorId: '456', + const connectors: AIConnector[] = [ + { + id: '123', actionTypeId: '.gen-ai', - provider: OpenAiProviderType.AzureAi, - defaultSystemPromptId: '2', - model: 'gpt-3', + apiProvider: OpenAiProviderType.OpenAi, + config: { + provider: OpenAiProviderType.OpenAi, + }, }, - }); - }); - - test('should return an empty object when no connectors are provided and default connector is missing', () => { - const result = getConversationApiConfig({ - allSystemPrompts, - conversation, - }); - - expect(result).toEqual({}); - }); - - test('should return the default system prompt if conversation system prompt is not found', () => { - const conversationWithMissingSystemPrompt: Conversation = { - ...conversation, - apiConfig: { - ...conversation.apiConfig, - defaultSystemPromptId: '999', - } as Conversation['apiConfig'], - }; - - const result = getConversationApiConfig({ - allSystemPrompts, - conversation: conversationWithMissingSystemPrompt, - connectors, - defaultConnector, - }); - - expect(result).toEqual({ - apiConfig: { - connectorId: '123', + { + id: '456', actionTypeId: '.gen-ai', - provider: OpenAiProviderType.OpenAi, - defaultSystemPromptId: '2', // Returns the default system prompt for new conversations - model: 'gpt-3', + apiProvider: OpenAiProviderType.AzureAi, }, - }); - }); + ] as AIConnector[]; - test('should return the correct config when connectors are not provided', () => { - const result = getConversationApiConfig({ - allSystemPrompts, - conversation, - defaultConnector, - }); + const defaultConnector: AIConnector = { + id: '456', + actionTypeId: '.gen-ai', + apiProvider: OpenAiProviderType.AzureAi, + } as AIConnector; - expect(result).toEqual({ - apiConfig: { - connectorId: '456', - actionTypeId: '.gen-ai', - provider: OpenAiProviderType.AzureAi, - defaultSystemPromptId: '2', - model: 'gpt-3', - }, - }); - }); + test('should return the correct API config when connector and system prompt are found', () => { + const result = getConversationApiConfig({ + allSystemPrompts, + conversation, + connectors, + defaultConnector, + }); - test('should return the first system prompt if both conversation system prompt and default new system prompt do not exist', () => { - const allSystemPromptsNoDefault: PromptResponse[] = allSystemPrompts.filter( - ({ isNewConversationDefault }) => isNewConversationDefault !== true - ); + expect(result).toEqual({ + apiConfig: { + connectorId: '123', + actionTypeId: '.gen-ai', + provider: OpenAiProviderType.OpenAi, + defaultSystemPromptId: '2', + model: 'gpt-3', + }, + }); + }); - const conversationWithoutSystemPrompt: Conversation = { - ...conversation, - apiConfig: { connectorId: '123', actionTypeId: '.gen-ai' }, - }; + test('should return the default connector when specific connector is not found', () => { + const conversationWithMissingConnector: Conversation = { + ...conversation, + apiConfig: { ...conversation.apiConfig, connectorId: '999' } as Conversation['apiConfig'], + }; - const result = getConversationApiConfig({ - allSystemPrompts: allSystemPromptsNoDefault, - conversation: conversationWithoutSystemPrompt, - connectors, - defaultConnector, - }); + const result = getConversationApiConfig({ + allSystemPrompts, + conversation: conversationWithMissingConnector, + connectors, + defaultConnector, + }); - expect(result).toEqual({ - apiConfig: { - connectorId: '123', - actionTypeId: '.gen-ai', - provider: OpenAiProviderType.OpenAi, - defaultSystemPromptId: '1', // Uses the first prompt in the list - model: undefined, // default connector's model - }, + expect(result).toEqual({ + apiConfig: { + connectorId: '456', + actionTypeId: '.gen-ai', + provider: OpenAiProviderType.AzureAi, + defaultSystemPromptId: '2', + model: 'gpt-3', + }, + }); }); - }); - - test('should return the first system prompt if conversation system prompt does not exist within all system prompts', () => { - const allSystemPromptsNoDefault: PromptResponse[] = allSystemPrompts.filter( - ({ isNewConversationDefault }) => isNewConversationDefault !== true - ); - const conversationWithoutSystemPrompt: Conversation = { - ...conversation, - apiConfig: { connectorId: '123', actionTypeId: '.gen-ai' }, - id: '4', // this id does not exist within allSystemPrompts - }; + test('should return an empty object when no connectors are provided and default connector is missing', () => { + const result = getConversationApiConfig({ + allSystemPrompts, + conversation, + }); - const result = getConversationApiConfig({ - allSystemPrompts: allSystemPromptsNoDefault, - conversation: conversationWithoutSystemPrompt, - connectors, - defaultConnector, + expect(result).toEqual({ + apiConfig: { + defaultSystemPromptId: '2', + }, + }); }); - expect(result).toEqual({ - apiConfig: { - connectorId: '123', - actionTypeId: '.gen-ai', - provider: OpenAiProviderType.OpenAi, - defaultSystemPromptId: '1', // Uses the first prompt in the list - model: undefined, // default connector's model - }, - }); - }); + test('should set default system prompt as undefined if conversation system prompt is not found', () => { + const conversationWithMissingSystemPrompt: Conversation = { + ...conversation, + apiConfig: { + ...conversation.apiConfig, + defaultSystemPromptId: '999', + } as Conversation['apiConfig'], + }; - test('should return the new default system prompt if defaultSystemPromptId is undefined', () => { - const conversationWithUndefinedPrompt: Conversation = { - ...conversation, - apiConfig: { - ...conversation.apiConfig, - defaultSystemPromptId: undefined, - } as Conversation['apiConfig'], - }; + const result = getConversationApiConfig({ + allSystemPrompts, + conversation: conversationWithMissingSystemPrompt, + connectors, + defaultConnector, + }); - const result = getConversationApiConfig({ - allSystemPrompts, - conversation: conversationWithUndefinedPrompt, - connectors, - defaultConnector, + expect(result).toEqual({ + apiConfig: { + connectorId: '123', + actionTypeId: '.gen-ai', + provider: OpenAiProviderType.OpenAi, + model: 'gpt-3', + }, + }); }); - expect(result).toEqual({ - apiConfig: { - connectorId: '123', - actionTypeId: '.gen-ai', - provider: OpenAiProviderType.OpenAi, - defaultSystemPromptId: '1', - model: 'gpt-3', - }, + test('should return the correct config when connectors are not provided', () => { + const result = getConversationApiConfig({ + allSystemPrompts, + conversation, + defaultConnector, + }); + + expect(result).toEqual({ + apiConfig: { + connectorId: '456', + actionTypeId: '.gen-ai', + provider: OpenAiProviderType.AzureAi, + defaultSystemPromptId: '2', + model: 'gpt-3', + }, + }); }); }); }); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_conversation/helpers.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_conversation/helpers.ts index fde1c1d3d943c..dce5a1ab11388 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_conversation/helpers.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_conversation/helpers.ts @@ -6,10 +6,11 @@ */ import React from 'react'; -import { PromptResponse } from '@kbn/elastic-assistant-common'; +import { ApiConfig, PromptResponse } from '@kbn/elastic-assistant-common'; import { Conversation } from '../../assistant_context/types'; import { AIConnector } from '../../connectorland/connector_selector'; import { getGenAiConfig } from '../../connectorland/helpers'; +import { DEFAULT_SYSTEM_PROMPT_NAME } from '../../content/prompts/system/translations'; export interface CodeBlockDetails { type: QueryType; @@ -71,15 +72,19 @@ export const analyzeMarkdown = (markdown: string): CodeBlockDetails[] => { }; /** - * Returns the default system prompt + * Returns the new default system prompt, fallback to the default system prompt if not found * * @param allSystemPrompts All available System Prompts */ -export const getDefaultNewSystemPrompt = (allSystemPrompts: PromptResponse[]) => - allSystemPrompts.find((prompt) => prompt.isNewConversationDefault) ?? allSystemPrompts?.[0]; +export const getDefaultNewSystemPrompt = (allSystemPrompts: PromptResponse[]) => { + const fallbackSystemPrompt = allSystemPrompts.find( + (prompt) => prompt.name === DEFAULT_SYSTEM_PROMPT_NAME + ); + return allSystemPrompts.find((prompt) => prompt.isNewConversationDefault) ?? fallbackSystemPrompt; +}; /** - * Returns the default system prompt for a given (New Custom) conversation + * Returns the default system prompt for a given conversation * * @param allSystemPrompts All available System Prompts * @param conversation Conversation to get the default system prompt for @@ -94,29 +99,26 @@ export const getDefaultSystemPrompt = ({ const conversationSystemPrompt = allSystemPrompts.find( (prompt) => prompt.id === conversation?.apiConfig?.defaultSystemPromptId ); - const defaultNewSystemPrompt = getDefaultNewSystemPrompt(allSystemPrompts); - return conversationSystemPrompt?.id ? conversationSystemPrompt : defaultNewSystemPrompt; + return conversationSystemPrompt; }; /** - * Returns the default system prompt for an existing conversation that has never been given a system prompt + * Returns the default system prompt * * @param allSystemPrompts All available System Prompts * @param conversation Conversation to get the default system prompt for */ -export const getInitialDefaultSystemPrompt = ({ +export const getFallbackDefaultSystemPrompt = ({ allSystemPrompts, - conversation, }: { allSystemPrompts: PromptResponse[]; - conversation: Conversation | undefined; }): PromptResponse | undefined => { - const conversationSystemPrompt = allSystemPrompts.find( - (prompt) => prompt.id === conversation?.apiConfig?.defaultSystemPromptId + const fallbackSystemPrompt = allSystemPrompts.find( + (prompt) => prompt.name === DEFAULT_SYSTEM_PROMPT_NAME ); - return conversationSystemPrompt ?? allSystemPrompts?.[0]; + return fallbackSystemPrompt; }; /** @@ -140,27 +142,29 @@ export const getConversationApiConfig = ({ }) => { const connector: AIConnector | undefined = connectors?.find((c) => c.id === conversation.apiConfig?.connectorId) ?? defaultConnector; - const connectorModel = getGenAiConfig(connector)?.defaultModel; - const defaultSystemPrompt = - conversation.apiConfig?.defaultSystemPromptId == null - ? getInitialDefaultSystemPrompt({ - allSystemPrompts, - conversation, - }) - : getDefaultSystemPrompt({ - allSystemPrompts, - conversation, - }); + + const { apiProvider: connectorApiProvider, defaultModel: connectorModel } = + getGenAiConfig(connector) ?? {}; + + const defaultSystemPrompt = getDefaultSystemPrompt({ + allSystemPrompts, + conversation, + }); return connector ? { apiConfig: { connectorId: connector.id, actionTypeId: connector.actionTypeId, - provider: connector.apiProvider, + provider: connector.apiProvider ?? connectorApiProvider, defaultSystemPromptId: defaultSystemPrompt?.id, model: conversation?.apiConfig?.model ?? connectorModel, }, } - : {}; + : ({ + // Scenario when no connectors is configured + apiConfig: { + defaultSystemPromptId: defaultSystemPrompt?.id, + }, + } as unknown as { apiConfig: ApiConfig }); }; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_send_message/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_send_message/index.tsx index 77e9ee8e6a45e..93bd03607e71f 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_send_message/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_send_message/index.tsx @@ -41,10 +41,8 @@ export const useSendMessage = (): UseSendMessage => { try { return await fetchConnectorExecuteAction({ conversationId, - isEnabledRAGAlerts: knowledgeBase.isEnabledRAGAlerts, // settings toggle alertsIndexPattern, apiConfig, - isEnabledKnowledgeBase: knowledgeBase.isEnabledKnowledgeBase, assistantStreamingEnabled, http, message, @@ -57,14 +55,7 @@ export const useSendMessage = (): UseSendMessage => { setIsLoading(false); } }, - [ - alertsIndexPattern, - assistantStreamingEnabled, - knowledgeBase.isEnabledRAGAlerts, - knowledgeBase.isEnabledKnowledgeBase, - knowledgeBase.latestAlerts, - traceOptions, - ] + [alertsIndexPattern, assistantStreamingEnabled, knowledgeBase.latestAlerts, traceOptions] ); const cancelRequest = useCallback(() => { diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings_management/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings_management/index.tsx index f144253ea4cce..afa8bd48567a2 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings_management/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings_management/index.tsx @@ -14,6 +14,7 @@ import { EuiText, EuiTitle, } from '@elastic/eui'; +import { css } from '@emotion/react'; import React, { useCallback } from 'react'; import { useAssistantContext } from '../../assistant_context'; @@ -32,13 +33,17 @@ const ConnectorsSettingsManagementComponent: React.FC = () => { return ( - +

{i18n.CONNECTOR_SETTINGS_MANAGEMENT_TITLE}

- - {i18n.CONNECTOR_SETTINGS_MANAGEMENT_DESCRIPTION} + + {i18n.CONNECTOR_SETTINGS_MANAGEMENT_DESCRIPTION} diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings_management/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings_management/translations.ts index 941337761fadc..e7f7ac69a7d1c 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings_management/translations.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings_management/translations.ts @@ -10,7 +10,7 @@ import { i18n } from '@kbn/i18n'; export const CONNECTOR_SETTINGS_MANAGEMENT_TITLE = i18n.translate( 'xpack.elasticAssistant.connectors.connectorSettingsManagement.title', { - defaultMessage: 'Connector Settings', + defaultMessage: 'Settings', } ); @@ -18,7 +18,7 @@ export const CONNECTOR_SETTINGS_MANAGEMENT_DESCRIPTION = i18n.translate( 'xpack.elasticAssistant.connectors.connectorSettingsManagement.description', { defaultMessage: - 'Using the Elastic AI Assistant requires setting up a connector with API access to OpenAI or Bedrock large language models. ', + 'To use Elastic AI Assistant, you must set up a connector to an external large language model.', } ); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings/translations.ts index 82d0b7ec47701..0d4ea885aeffc 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings/translations.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings/translations.ts @@ -38,6 +38,6 @@ export const SETTINGS_DESCRIPTION = i18n.translate( 'xpack.elasticAssistant.dataAnonymization.settings.anonymizationSettings.settingsDescription', { defaultMessage: - "When adding Prompt Context throughout the Security App that may contain sensitive information, you can choose which fields are sent, and whether to enable anonymization for these fields. This will replace the field's value with a random string before sending the conversation. Helpful defaults are provided below.", + 'Define privacy settings for event data sent to third-party LLM providers. You can choose which fields to include, and which to anonymize by replacing their values with random strings. Helpful defaults are provided below.', } ); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings/use_anonymization_list_update.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings/use_anonymization_list_update.tsx index f9ee4875fad23..643a2ca8d7c39 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings/use_anonymization_list_update.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings/use_anonymization_list_update.tsx @@ -31,7 +31,6 @@ export const useAnonymizationListUpdate = ({ const onListUpdated = useCallback( async (updates: BatchUpdateListItem[]) => { const updatedFieldsKeys = updates.map((u) => u.field); - const updatedFields = updates.map((u) => ({ ...(anonymizationFields.data.find((f) => f.field === u.field) ?? { id: '', field: '' }), ...(u.update === 'allow' || u.update === 'defaultAllow' diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings_management/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings_management/index.tsx index 3e3812510f076..420f570834cce 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings_management/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings_management/index.tsx @@ -5,71 +5,125 @@ * 2.0. */ -import { EuiFlexGroup, EuiPanel, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui'; -import React from 'react'; +import { EuiFlexGroup, EuiPanel, EuiSpacer, EuiText } from '@elastic/eui'; +import React, { useCallback, useState } from 'react'; -import { FindAnonymizationFieldsResponse } from '@kbn/elastic-assistant-common/impl/schemas/anonymization_fields/find_anonymization_fields_route.gen'; -import { PerformBulkActionRequestBody } from '@kbn/elastic-assistant-common/impl/schemas/anonymization_fields/bulk_crud_anonymization_fields_route.gen'; import { euiThemeVars } from '@kbn/ui-theme'; import { Stats } from '../../../data_anonymization_editor/stats'; import { ContextEditor } from '../../../data_anonymization_editor/context_editor'; import * as i18n from '../anonymization_settings/translations'; import { useAnonymizationListUpdate } from '../anonymization_settings/use_anonymization_list_update'; +import { + DEFAULT_ANONYMIZATION_FIELDS, + DEFAULT_CONVERSATIONS, + DEFAULT_PROMPTS, + useSettingsUpdater, +} from '../../../assistant/settings/use_settings_updater/use_settings_updater'; +import { useFetchAnonymizationFields } from '../../../assistant/api/anonymization_fields/use_fetch_anonymization_fields'; +import { AssistantSettingsBottomBar } from '../../../assistant/settings/assistant_settings_bottom_bar'; +import { useAssistantContext } from '../../../assistant_context'; +import { SETTINGS_UPDATED_TOAST_TITLE } from '../../../assistant/settings/translations'; export interface Props { defaultPageSize?: number; - anonymizationFields: FindAnonymizationFieldsResponse; - anonymizationFieldsBulkActions: PerformBulkActionRequestBody; - setAnonymizationFieldsBulkActions: React.Dispatch< - React.SetStateAction - >; - setUpdatedAnonymizationData: React.Dispatch< - React.SetStateAction - >; } -const AnonymizationSettingsManagementComponent: React.FC = ({ - defaultPageSize, - anonymizationFields, - anonymizationFieldsBulkActions, - setAnonymizationFieldsBulkActions, - setUpdatedAnonymizationData, -}) => { - const onListUpdated = useAnonymizationListUpdate({ - anonymizationFields, +const AnonymizationSettingsManagementComponent: React.FC = ({ defaultPageSize = 5 }) => { + const { toasts } = useAssistantContext(); + const { data: anonymizationFields } = useFetchAnonymizationFields(); + const [hasPendingChanges, setHasPendingChanges] = useState(false); + + const { anonymizationFieldsBulkActions, setAnonymizationFieldsBulkActions, setUpdatedAnonymizationData, + resetSettings, + saveSettings, + updatedAnonymizationData, + } = useSettingsUpdater( + DEFAULT_CONVERSATIONS, // Anonymization settings do not require conversations + DEFAULT_PROMPTS, // Anonymization settings do not require prompts + false, // Anonymization settings do not require conversations + false, // Anonymization settings do not require prompts + anonymizationFields ?? DEFAULT_ANONYMIZATION_FIELDS + ); + + const onCancelClick = useCallback(() => { + resetSettings(); + setHasPendingChanges(false); + }, [resetSettings]); + + const handleSave = useCallback( + async (param?: { callback?: () => void }) => { + await saveSettings(); + toasts?.addSuccess({ + iconType: 'check', + title: SETTINGS_UPDATED_TOAST_TITLE, + }); + setHasPendingChanges(false); + param?.callback?.(); + }, + [saveSettings, toasts] + ); + + const onSaveButtonClicked = useCallback(() => { + handleSave(); + }, [handleSave]); + + const handleAnonymizationFieldsBulkActions = useCallback( + (value) => { + setHasPendingChanges(true); + setAnonymizationFieldsBulkActions(value); + }, + [setAnonymizationFieldsBulkActions] + ); + + const handleUpdatedAnonymizationData = useCallback( + (value) => { + setHasPendingChanges(true); + setUpdatedAnonymizationData(value); + }, + [setUpdatedAnonymizationData] + ); + + const onListUpdated = useAnonymizationListUpdate({ + anonymizationFields: updatedAnonymizationData, + anonymizationFieldsBulkActions, + setAnonymizationFieldsBulkActions: handleAnonymizationFieldsBulkActions, + setUpdatedAnonymizationData: handleUpdatedAnonymizationData, }); return ( - - -

{i18n.SETTINGS_TITLE}

-
- - {i18n.SETTINGS_DESCRIPTION} - - - - - - + <> + + {i18n.SETTINGS_DESCRIPTION} + + - + + + - + + + + -
+ ); }; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/get_columns/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/get_columns/index.tsx index 66d3a89a65df8..cc08b0a68ab89 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/get_columns/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/get_columns/index.tsx @@ -19,13 +19,15 @@ const AnonymizedButton = styled(EuiButtonEmpty)` `; export const getColumns = ({ + compressed = true, + hasUpdateAIAssistantAnonymization, onListUpdated, rawData, - hasUpdateAIAssistantAnonymization, }: { + compressed?: boolean; + hasUpdateAIAssistantAnonymization: boolean; onListUpdated: (updates: BatchUpdateListItem[]) => void; rawData: Record | null; - hasUpdateAIAssistantAnonymization: boolean; }): Array> => { const actionsColumn: EuiBasicTableColumn = { field: FIELDS.ACTIONS, @@ -68,6 +70,7 @@ export const getColumns = ({ disabled={!hasUpdateAIAssistantAnonymization} label="" showLabel={false} + compressed={compressed} onChange={() => { onListUpdated([ { diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/index.tsx index 13ed9bd866513..6138a907f285b 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/index.tsx @@ -98,8 +98,8 @@ const ContextEditorComponent: React.FC = ({ ); const columns = useMemo( - () => getColumns({ onListUpdated, rawData, hasUpdateAIAssistantAnonymization }), - [hasUpdateAIAssistantAnonymization, onListUpdated, rawData] + () => getColumns({ onListUpdated, rawData, hasUpdateAIAssistantAnonymization, compressed }), + [hasUpdateAIAssistantAnonymization, onListUpdated, rawData, compressed] ); const rows = useMemo( diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.test.tsx index 4d39504075c7e..e5bac53d3d1ab 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.test.tsx @@ -94,78 +94,6 @@ describe('Knowledge base settings', () => { expect(getByTestId('esql-installed')).toBeInTheDocument(); expect(queryByTestId('install-esql')).not.toBeInTheDocument(); - expect(getByTestId('esqlEnableButton')).toBeInTheDocument(); - }); - it('On click enable esql button, esql is enabled', () => { - (useKnowledgeBaseStatus as jest.Mock).mockImplementation(() => { - return { - data: { - elser_exists: true, - esql_exists: false, - index_exists: true, - pipeline_exists: true, - }, - isLoading: false, - isFetching: false, - }; - }); - const { getByTestId, queryByTestId } = render( - - - - ); - expect(queryByTestId('esql-installed')).not.toBeInTheDocument(); - expect(getByTestId('install-esql')).toBeInTheDocument(); - fireEvent.click(getByTestId('esqlEnableButton')); - expect(mockSetup).toHaveBeenCalledWith('esql'); - }); - it('On disable lang chain, set isEnabledKnowledgeBase to false', () => { - const { getByTestId } = render( - - - - ); - fireEvent.click(getByTestId('isEnabledKnowledgeBaseSwitch')); - expect(setUpdatedKnowledgeBaseSettings).toHaveBeenCalledWith({ - isEnabledRAGAlerts: false, - isEnabledKnowledgeBase: false, - latestAlerts: DEFAULT_LATEST_ALERTS, - }); - - expect(mockSetup).not.toHaveBeenCalled(); - }); - it('On enable lang chain, set up with esql by default if ELSER exists', () => { - const { getByTestId } = render( - - - - ); - fireEvent.click(getByTestId('isEnabledKnowledgeBaseSwitch')); - expect(setUpdatedKnowledgeBaseSettings).toHaveBeenCalledWith({ - isEnabledKnowledgeBase: true, - isEnabledRAGAlerts: false, - latestAlerts: DEFAULT_LATEST_ALERTS, - }); - - expect(mockSetup).toHaveBeenCalledWith('esql'); - }); - it('On disable knowledge base, call delete knowledge base setup', () => { - const { getByTestId, queryByTestId } = render( - - - - ); - expect(queryByTestId('install-kb')).not.toBeInTheDocument(); - expect(getByTestId('kb-installed')).toBeInTheDocument(); - fireEvent.click(getByTestId('knowledgeBaseActionButton')); - expect(mockDelete).toHaveBeenCalledWith(); }); it('On enable knowledge base, call setup knowledge base setup', () => { (useKnowledgeBaseStatus as jest.Mock).mockImplementation(() => { @@ -187,8 +115,8 @@ describe('Knowledge base settings', () => { ); expect(queryByTestId('kb-installed')).not.toBeInTheDocument(); expect(getByTestId('install-kb')).toBeInTheDocument(); - fireEvent.click(getByTestId('knowledgeBaseActionButton')); - expect(mockSetup).toHaveBeenCalledWith(); + fireEvent.click(getByTestId('setupKnowledgeBaseButton')); + expect(mockSetup).toHaveBeenCalledWith('esql'); }); it('If elser does not exist, do not offer knowledge base', () => { (useKnowledgeBaseStatus as jest.Mock).mockImplementation(() => { @@ -210,14 +138,4 @@ describe('Knowledge base settings', () => { ); expect(queryByTestId('knowledgeBaseActionButton')).not.toBeInTheDocument(); }); - - it('renders the alerts settings', () => { - const { getByTestId } = render( - - - - ); - - expect(getByTestId('alertsSwitch')).toBeInTheDocument(); - }); }); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.tsx index fc152d1e5a3da..a5abed3e42f53 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.tsx @@ -11,17 +11,13 @@ import { EuiTitle, EuiText, EuiHorizontalRule, - EuiLoadingSpinner, EuiSpacer, - EuiSwitchEvent, - EuiLink, EuiBetaBadge, EuiFlexGroup, EuiFlexItem, EuiHealth, EuiButtonEmpty, - EuiToolTip, - EuiSwitch, + EuiLink, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { css } from '@emotion/react'; @@ -30,12 +26,10 @@ import { AlertsSettings } from '../alerts/settings/alerts_settings'; import { useAssistantContext } from '../assistant_context'; import type { KnowledgeBaseConfig } from '../assistant/types'; import * as i18n from './translations'; -import { useDeleteKnowledgeBase } from '../assistant/api/knowledge_base/use_delete_knowledge_base'; import { useKnowledgeBaseStatus } from '../assistant/api/knowledge_base/use_knowledge_base_status'; import { useSetupKnowledgeBase } from '../assistant/api/knowledge_base/use_setup_knowledge_base'; const ESQL_RESOURCE = 'esql'; -const KNOWLEDGE_BASE_INDEX_PATTERN_OLD = '.kibana-elastic-ai-assistant-kb'; const KNOWLEDGE_BASE_INDEX_PATTERN = '.kibana-elastic-ai-assistant-knowledge-base-(SPACE)'; interface Props { @@ -44,179 +38,77 @@ interface Props { } /** - * Knowledge Base Settings -- enable and disable LangChain integration, Knowledge Base, and ESQL KB Documents + * Knowledge Base Settings -- set up the Knowledge Base and configure RAG on alerts */ export const KnowledgeBaseSettings: React.FC = React.memo( ({ knowledgeBase, setUpdatedKnowledgeBaseSettings }) => { - const { - assistantFeatures: { assistantKnowledgeBaseByDefault: enableKnowledgeBaseByDefault }, - http, - } = useAssistantContext(); + const { http } = useAssistantContext(); const { data: kbStatus, isLoading, isFetching, } = useKnowledgeBaseStatus({ http, resource: ESQL_RESOURCE }); const { mutate: setupKB, isLoading: isSettingUpKB } = useSetupKnowledgeBase({ http }); - const { mutate: deleteKB, isLoading: isDeletingUpKB } = useDeleteKnowledgeBase({ http }); // Resource enabled state const isElserEnabled = kbStatus?.elser_exists ?? false; - const isKnowledgeBaseEnabled = (kbStatus?.index_exists && kbStatus?.pipeline_exists) ?? false; const isESQLEnabled = kbStatus?.esql_exists ?? false; + const isKnowledgeBaseSetup = + (isElserEnabled && isESQLEnabled && kbStatus?.index_exists && kbStatus?.pipeline_exists) ?? + false; const isSetupInProgress = kbStatus?.is_setup_in_progress ?? false; // Resource availability state - const isLoadingKb = - isLoading || isFetching || isSettingUpKB || isDeletingUpKB || isSetupInProgress; - const isKnowledgeBaseAvailable = knowledgeBase.isEnabledKnowledgeBase && kbStatus?.elser_exists; - const isESQLAvailable = - knowledgeBase.isEnabledKnowledgeBase && isKnowledgeBaseAvailable && isKnowledgeBaseEnabled; - // Prevent enabling if elser doesn't exist, but always allow to disable - const isSwitchDisabled = enableKnowledgeBaseByDefault - ? false - : !kbStatus?.elser_exists && !knowledgeBase.isEnabledKnowledgeBase; + const isLoadingKb = isLoading || isFetching || isSettingUpKB || isSetupInProgress; // Calculated health state for EuiHealth component const elserHealth = isElserEnabled ? 'success' : 'subdued'; - const knowledgeBaseHealth = isKnowledgeBaseEnabled ? 'success' : 'subdued'; + const knowledgeBaseHealth = isKnowledgeBaseSetup ? 'success' : 'subdued'; const esqlHealth = isESQLEnabled ? 'success' : 'subdued'; ////////////////////////////////////////////////////////////////////////////////////////// - // Main `Knowledge Base` switch, which toggles the `isEnabledKnowledgeBase` UI feature toggle - // setting that is saved to localstorage - const onEnableAssistantLangChainChange = useCallback( - (event: EuiSwitchEvent) => { - setUpdatedKnowledgeBaseSettings({ - ...knowledgeBase, - isEnabledKnowledgeBase: event.target.checked, - }); - - // If enabling and ELSER exists or automatic KB setup FF is enabled, try to set up automatically - if (event.target.checked && (enableKnowledgeBaseByDefault || kbStatus?.elser_exists)) { - setupKB(ESQL_RESOURCE); - } - }, - [ - enableKnowledgeBaseByDefault, - kbStatus?.elser_exists, - knowledgeBase, - setUpdatedKnowledgeBaseSettings, - setupKB, - ] - ); + // Main `Knowledge Base` setup button + const onSetupKnowledgeBaseButtonClick = useCallback(() => { + setupKB(ESQL_RESOURCE); + }, [setupKB]); - const isEnabledKnowledgeBaseSwitch = useMemo(() => { - return isLoadingKb ? ( - - ) : ( - - - - ); - }, [ - isLoadingKb, - isSwitchDisabled, - knowledgeBase.isEnabledKnowledgeBase, - onEnableAssistantLangChainChange, - ]); - - ////////////////////////////////////////////////////////////////////////////////////////// - // Knowledge Base Resource - const onEnableKB = useCallback( - (enabled: boolean) => { - if (enabled) { - setupKB(); - } else { - deleteKB(); - } - }, - [deleteKB, setupKB] - ); - - const knowledgeBaseActionButton = useMemo(() => { - return isLoadingKb || !isKnowledgeBaseAvailable ? ( + const setupKnowledgeBaseButton = useMemo(() => { + return isKnowledgeBaseSetup ? ( <> ) : ( onEnableKB(!isKnowledgeBaseEnabled)} + color={'primary'} + data-test-subj={'setupKnowledgeBaseButton'} + onClick={onSetupKnowledgeBaseButtonClick} size="xs" + isLoading={isLoadingKb} > - {isKnowledgeBaseEnabled - ? i18n.KNOWLEDGE_BASE_DELETE_BUTTON - : i18n.KNOWLEDGE_BASE_INIT_BUTTON} + {i18n.SETUP_KNOWLEDGE_BASE_BUTTON} ); - }, [isKnowledgeBaseAvailable, isKnowledgeBaseEnabled, isLoadingKb, onEnableKB]); + }, [isKnowledgeBaseSetup, isLoadingKb, onSetupKnowledgeBaseButtonClick]); + ////////////////////////////////////////////////////////////////////////////////////////// + // Knowledge Base Resource const knowledgeBaseDescription = useMemo(() => { - return isKnowledgeBaseEnabled ? ( + return isKnowledgeBaseSetup ? ( - {i18n.KNOWLEDGE_BASE_DESCRIPTION_INSTALLED( - enableKnowledgeBaseByDefault - ? KNOWLEDGE_BASE_INDEX_PATTERN - : KNOWLEDGE_BASE_INDEX_PATTERN_OLD - )}{' '} - {knowledgeBaseActionButton} + {i18n.KNOWLEDGE_BASE_DESCRIPTION_INSTALLED(KNOWLEDGE_BASE_INDEX_PATTERN)} ) : ( - - {i18n.KNOWLEDGE_BASE_DESCRIPTION} {knowledgeBaseActionButton} - + {i18n.KNOWLEDGE_BASE_DESCRIPTION} ); - }, [enableKnowledgeBaseByDefault, isKnowledgeBaseEnabled, knowledgeBaseActionButton]); + }, [isKnowledgeBaseSetup]); ////////////////////////////////////////////////////////////////////////////////////////// // ESQL Resource - const onEnableESQL = useCallback( - (enabled: boolean) => { - if (enabled) { - setupKB(ESQL_RESOURCE); - } else { - deleteKB(ESQL_RESOURCE); - } - }, - [deleteKB, setupKB] - ); - - const esqlActionButton = useMemo(() => { - return isLoadingKb || !isESQLAvailable ? ( - <> - ) : ( - onEnableESQL(!isESQLEnabled)} - size="xs" - > - {isESQLEnabled ? i18n.KNOWLEDGE_BASE_DELETE_BUTTON : i18n.KNOWLEDGE_BASE_INIT_BUTTON} - - ); - }, [isLoadingKb, isESQLAvailable, isESQLEnabled, onEnableESQL]); - const esqlDescription = useMemo(() => { return isESQLEnabled ? ( - - {i18n.ESQL_DESCRIPTION_INSTALLED} {esqlActionButton} - + {i18n.ESQL_DESCRIPTION_INSTALLED} ) : ( - - {i18n.ESQL_DESCRIPTION} {esqlActionButton} - + {i18n.ESQL_DESCRIPTION} ); - }, [esqlActionButton, isESQLEnabled]); + }, [isESQLEnabled]); return ( <> @@ -227,7 +119,23 @@ export const KnowledgeBaseSettings: React.FC = React.memo(
- {i18n.SETTINGS_DESCRIPTION} + + + {i18n.KNOWLEDGE_BASE_DOCUMENTATION} + + ), + }} + /> + = React.memo( } `} > - {isEnabledKnowledgeBaseSwitch} + {setupKnowledgeBaseButton} @@ -261,30 +169,8 @@ export const KnowledgeBaseSettings: React.FC = React.memo( `} > - {i18n.KNOWLEDGE_BASE_ELSER_MACHINE_LEARNING} - - ), - seeDocs: ( - - {i18n.KNOWLEDGE_BASE_ELSER_SEE_DOCS} - - ), - }} /> diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management.tsx new file mode 100644 index 0000000000000..49be2956e749a --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management.tsx @@ -0,0 +1,257 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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, useMemo, useState } from 'react'; +import { + EuiFormRow, + EuiText, + EuiHorizontalRule, + EuiSpacer, + EuiLink, + EuiFlexGroup, + EuiFlexItem, + EuiHealth, + EuiButtonEmpty, + EuiPanel, +} from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { css } from '@emotion/react'; + +import { AlertsSettings } from '../alerts/settings/alerts_settings'; +import { useAssistantContext } from '../assistant_context'; +import * as i18n from './translations'; +import { useKnowledgeBaseStatus } from '../assistant/api/knowledge_base/use_knowledge_base_status'; +import { useSetupKnowledgeBase } from '../assistant/api/knowledge_base/use_setup_knowledge_base'; +import { + useSettingsUpdater, + DEFAULT_CONVERSATIONS, + DEFAULT_PROMPTS, +} from '../assistant/settings/use_settings_updater/use_settings_updater'; +import { AssistantSettingsBottomBar } from '../assistant/settings/assistant_settings_bottom_bar'; +import { SETTINGS_UPDATED_TOAST_TITLE } from '../assistant/settings/translations'; + +const ESQL_RESOURCE = 'esql'; +const KNOWLEDGE_BASE_INDEX_PATTERN = '.kibana-elastic-ai-assistant-knowledge-base-(SPACE)'; + +/** + * Knowledge Base Settings -- set up the Knowledge Base and configure RAG on alerts + */ +export const KnowledgeBaseSettingsManagement: React.FC = React.memo(() => { + const { http, toasts } = useAssistantContext(); + const [hasPendingChanges, setHasPendingChanges] = useState(false); + + const { knowledgeBase, setUpdatedKnowledgeBaseSettings, resetSettings, saveSettings } = + useSettingsUpdater( + DEFAULT_CONVERSATIONS, // Knowledge Base settings do not require conversations + DEFAULT_PROMPTS, // Knowledge Base settings do not require prompts + false, // Knowledge Base settings do not require prompts + false // Knowledge Base settings do not require conversations + ); + + const handleSave = useCallback( + async (param?: { callback?: () => void }) => { + await saveSettings(); + toasts?.addSuccess({ + iconType: 'check', + title: SETTINGS_UPDATED_TOAST_TITLE, + }); + setHasPendingChanges(false); + param?.callback?.(); + }, + [saveSettings, toasts] + ); + + const handleUpdateKnowledgeBaseSettings = useCallback( + (updatedKnowledgebase) => { + setHasPendingChanges(true); + setUpdatedKnowledgeBaseSettings(updatedKnowledgebase); + }, + [setUpdatedKnowledgeBaseSettings] + ); + + const onCancelClick = useCallback(() => { + resetSettings(); + setHasPendingChanges(false); + }, [resetSettings]); + + const onSaveButtonClicked = useCallback(() => { + handleSave(); + }, [handleSave]); + + const { + data: kbStatus, + isLoading, + isFetching, + } = useKnowledgeBaseStatus({ http, resource: ESQL_RESOURCE }); + const { mutate: setupKB, isLoading: isSettingUpKB } = useSetupKnowledgeBase({ http }); + + // Resource enabled state + const isElserEnabled = kbStatus?.elser_exists ?? false; + const isESQLEnabled = kbStatus?.esql_exists ?? false; + const isKnowledgeBaseSetup = + (isElserEnabled && isESQLEnabled && kbStatus?.index_exists && kbStatus?.pipeline_exists) ?? + false; + const isSetupInProgress = kbStatus?.is_setup_in_progress ?? false; + + // Resource availability state + const isLoadingKb = isLoading || isFetching || isSettingUpKB || isSetupInProgress; + + // Calculated health state for EuiHealth component + const elserHealth = isElserEnabled ? 'success' : 'subdued'; + const knowledgeBaseHealth = isKnowledgeBaseSetup ? 'success' : 'subdued'; + const esqlHealth = isESQLEnabled ? 'success' : 'subdued'; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Main `Knowledge Base` setup button + const onSetupKnowledgeBaseButtonClick = useCallback(() => { + setupKB(ESQL_RESOURCE); + }, [setupKB]); + + const setupKnowledgeBaseButton = useMemo(() => { + return isKnowledgeBaseSetup ? ( + <> + ) : ( + + {i18n.SETUP_KNOWLEDGE_BASE_BUTTON} + + ); + }, [isKnowledgeBaseSetup, isLoadingKb, onSetupKnowledgeBaseButtonClick]); + + ////////////////////////////////////////////////////////////////////////////////////////// + // Knowledge Base Resource + const knowledgeBaseDescription = useMemo(() => { + return isKnowledgeBaseSetup ? ( + + {i18n.KNOWLEDGE_BASE_DESCRIPTION_INSTALLED(KNOWLEDGE_BASE_INDEX_PATTERN)} + + ) : ( + {i18n.KNOWLEDGE_BASE_DESCRIPTION} + ); + }, [isKnowledgeBaseSetup]); + + ////////////////////////////////////////////////////////////////////////////////////////// + // ESQL Resource + + const esqlDescription = useMemo(() => { + return isESQLEnabled ? ( + {i18n.ESQL_DESCRIPTION_INSTALLED} + ) : ( + {i18n.ESQL_DESCRIPTION} + ); + }, [isESQLEnabled]); + + return ( + + + + {i18n.KNOWLEDGE_BASE_DOCUMENTATION} + + ), + }} + /> + + + + + {setupKnowledgeBaseButton} + + + + + +
+ {i18n.KNOWLEDGE_BASE_ELSER_LABEL} + + + +
+
+ +
+ {i18n.KNOWLEDGE_BASE_LABEL} + + {knowledgeBaseDescription} + +
+
+ + + {i18n.ESQL_LABEL} + + {esqlDescription} + + + +
+ + + + + + +
+ ); +}); + +KnowledgeBaseSettingsManagement.displayName = 'KnowledgeBaseSettingsManagement'; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/install_knowledge_base_button.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/setup_knowledge_base_button.tsx similarity index 70% rename from x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/install_knowledge_base_button.tsx rename to x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/setup_knowledge_base_button.tsx index 32e34eb59fa93..0d1de18e29eb6 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/install_knowledge_base_button.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/setup_knowledge_base_button.tsx @@ -16,16 +16,11 @@ import { useKnowledgeBaseStatus } from '../assistant/api/knowledge_base/use_know const ESQL_RESOURCE = 'esql'; /** - * Self-contained component that renders a button to install the knowledge base. + * Self-contained component that renders a button to set up the knowledge base. * - * Only renders if `assistantKnowledgeBaseByDefault` feature flag is enabled. */ -export const InstallKnowledgeBaseButton: React.FC = React.memo(() => { - const { - assistantFeatures: { assistantKnowledgeBaseByDefault: enableKnowledgeBaseByDefault }, - http, - toasts, - } = useAssistantContext(); +export const SetupKnowledgeBaseButton: React.FC = React.memo(() => { + const { http, toasts } = useAssistantContext(); const { data: kbStatus } = useKnowledgeBaseStatus({ http, resource: ESQL_RESOURCE }); const { mutate: setupKB, isLoading: isSettingUpKB } = useSetupKnowledgeBase({ http, toasts }); @@ -41,24 +36,24 @@ export const InstallKnowledgeBaseButton: React.FC = React.memo(() => { setupKB(ESQL_RESOURCE); }, [setupKB]); - if (!enableKnowledgeBaseByDefault || isSetupComplete) { + if (isSetupComplete) { return null; } return ( {i18n.translate('xpack.elasticAssistant.knowledgeBase.installKnowledgeBaseButton', { - defaultMessage: 'Install Knowledge Base', + defaultMessage: 'Setup Knowledge Base', })} ); }); -InstallKnowledgeBaseButton.displayName = 'InstallKnowledgeBaseButton'; +SetupKnowledgeBaseButton.displayName = 'SetupKnowledgeBaseButton'; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/translations.ts index e1b176e9dcaa7..edb8c1e857302 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/translations.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/translations.ts @@ -66,11 +66,10 @@ export const SETTINGS_BADGE = i18n.translate( } ); -export const SETTINGS_DESCRIPTION = i18n.translate( +export const KNOWLEDGE_BASE_DOCUMENTATION = i18n.translate( 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettings.settingsDescription', { - defaultMessage: - 'Powered by ELSER, the Knowledge Base enables the ability to recall documents and other relevant context within your conversation.', + defaultMessage: 'documentation', } ); @@ -81,6 +80,13 @@ export const KNOWLEDGE_BASE_LABEL = i18n.translate( } ); +export const SETUP_KNOWLEDGE_BASE_BUTTON = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettings.setupKnowledgeBaseButton', + { + defaultMessage: 'Setup', + } +); + export const KNOWLEDGE_BASE_TOOLTIP = i18n.translate( 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettings.knowledgeBaseTooltip', { diff --git a/x-pack/packages/kbn-entities-schema/src/schema/common.ts b/x-pack/packages/kbn-entities-schema/src/schema/common.ts index bb9d07b1957f4..df6d20ef1d44b 100644 --- a/x-pack/packages/kbn-entities-schema/src/schema/common.ts +++ b/x-pack/packages/kbn-entities-schema/src/schema/common.ts @@ -88,6 +88,11 @@ export const metadataSchema = z destination: z.optional(z.string()), limit: z.optional(z.number().default(1000)), }) + .transform((metadata) => ({ + ...metadata, + destination: metadata.destination ?? metadata.source, + limit: metadata.limit ?? 1000, + })) .or(z.string().transform((value) => ({ source: value, destination: value, limit: 1000 }))); export const identityFieldsSchema = z diff --git a/x-pack/packages/ml/aiops_log_rate_analysis/queries/fetch_significant_term_p_values.ts b/x-pack/packages/ml/aiops_log_rate_analysis/queries/fetch_significant_term_p_values.ts index 9017b4949c8fe..735dadc280b6b 100644 --- a/x-pack/packages/ml/aiops_log_rate_analysis/queries/fetch_significant_term_p_values.ts +++ b/x-pack/packages/ml/aiops_log_rate_analysis/queries/fetch_significant_term_p_values.ts @@ -28,7 +28,7 @@ import { getRequestBase } from './get_request_base'; export const getSignificantTermRequest = ( params: AiopsLogRateAnalysisSchema, - fieldName: string, + fieldNames: string[], { wrap }: RandomSamplerWrapper ): estypes.SearchRequest => { const query = getQueryWithParams({ @@ -56,18 +56,18 @@ export const getSignificantTermRequest = ( ]; } - const pValueAgg: Record< - 'sig_term_p_value' | 'distinct_count', - estypes.AggregationsAggregationContainer - > = { + const fieldCandidateAggs = fieldNames.reduce< + Record + >((aggs, fieldName, index) => { // Used to identify fields with only one distinct value which we'll ignore in the analysis. - distinct_count: { + aggs[`distinct_count_${index}`] = { cardinality: { field: fieldName, }, - }, - // Used to calculate the p-value for terms of the field. - sig_term_p_value: { + }; + + // Used to calculate the p-value for the field. + aggs[`sig_term_p_value_${index}`] = { significant_terms: { field: fieldName, background_filter: { @@ -90,13 +90,15 @@ export const getSignificantTermRequest = ( p_value: { background_is_superset: false }, size: 1000, }, - }, - }; + }; + + return aggs; + }, {}); const body = { query, size: 0, - aggs: wrap(pValueAgg), + aggs: wrap(fieldCandidateAggs), }; return { @@ -137,21 +139,20 @@ export const fetchSignificantTermPValues = async ({ const result: SignificantItem[] = []; - const settledPromises = await Promise.allSettled( - fieldNames.map((fieldName) => - esClient.search(getSignificantTermRequest(params, fieldName, randomSamplerWrapper), { - signal: abortSignal, - maxRetries: 0, - }) - ) + const resp = await esClient.search( + getSignificantTermRequest(params, fieldNames, randomSamplerWrapper), + { + signal: abortSignal, + maxRetries: 0, + } ); - function reportError(fieldName: string, error: unknown) { - if (!isRequestAbortedError(error)) { + if (resp.aggregations === undefined) { + if (!isRequestAbortedError(resp)) { if (logger) { logger.error( - `Failed to fetch p-value aggregation for fieldName "${fieldName}", got: \n${JSON.stringify( - error, + `Failed to fetch p-value aggregation for field names ${fieldNames.join()}, got: \n${JSON.stringify( + resp, null, 2 )}` @@ -159,40 +160,23 @@ export const fetchSignificantTermPValues = async ({ } if (emitError) { - emitError(`Failed to fetch p-value aggregation for fieldName "${fieldName}".`); + emitError(`Failed to fetch p-value aggregation for field names "${fieldNames.join()}".`); } } + return result; } - for (const [index, settledPromise] of settledPromises.entries()) { - const fieldName = fieldNames[index]; - - if (settledPromise.status === 'rejected') { - reportError(fieldName, settledPromise.reason); - // Still continue the analysis even if individual p-value queries fail. - continue; - } - - const resp = settledPromise.value; - - if (resp.aggregations === undefined) { - reportError(fieldName, resp); - // Still continue the analysis even if individual p-value queries fail. - continue; - } - - const overallResult = ( - randomSamplerWrapper.unwrap(resp.aggregations) as Record<'sig_term_p_value', Aggs> - ).sig_term_p_value; + const unwrappedResp = randomSamplerWrapper.unwrap(resp.aggregations) as Record; + for (const [index, fieldName] of fieldNames.entries()) { + const pValueBuckets = unwrappedResp[`sig_term_p_value_${index}`]; const distinctCount = ( - randomSamplerWrapper.unwrap(resp.aggregations) as Record< - 'distinct_count', - estypes.AggregationsCardinalityAggregate - > - ).distinct_count.value; + unwrappedResp[ + `distinct_count_${index}` + ] as unknown as estypes.AggregationsCardinalityAggregate + ).value; - for (const bucket of overallResult.buckets) { + for (const bucket of pValueBuckets.buckets) { const pValue = Math.exp(-bucket.score); if ( @@ -209,8 +193,8 @@ export const fetchSignificantTermPValues = async ({ fieldValue: String(bucket.key), doc_count: bucket.doc_count, bg_count: bucket.bg_count, - total_doc_count: overallResult.doc_count, - total_bg_count: overallResult.bg_count, + total_doc_count: pValueBuckets.doc_count, + total_bg_count: pValueBuckets.bg_count, score: bucket.score, pValue, normalizedScore: getNormalizedScore(bucket.score), diff --git a/x-pack/packages/ml/aiops_log_rate_analysis/queue_field_candidates.ts b/x-pack/packages/ml/aiops_log_rate_analysis/queue_field_candidates.ts new file mode 100644 index 0000000000000..9e8c458c66e63 --- /dev/null +++ b/x-pack/packages/ml/aiops_log_rate_analysis/queue_field_candidates.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 { isPopulatedObject } from '@kbn/ml-is-populated-object'; + +export const QUEUE_CHUNKING_SIZE = 50; + +export interface KeywordFieldCandidates { + keywordFieldCandidates: string[]; +} +export const isKeywordFieldCandidates = (d: unknown): d is KeywordFieldCandidates => + isPopulatedObject(d, ['keywordFieldCandidates']); + +export interface TextFieldCandidates { + textFieldCandidates: string[]; +} +export const isTextFieldCandidates = (d: unknown): d is KeywordFieldCandidates => + isPopulatedObject(d, ['textFieldCandidates']); + +export type QueueFieldCandidate = KeywordFieldCandidates | TextFieldCandidates; diff --git a/x-pack/packages/security-solution/data_table/common/types/detail_panel.ts b/x-pack/packages/security-solution/data_table/common/types/detail_panel.ts index 55fff6ffc7fd3..d14a0b8d35213 100644 --- a/x-pack/packages/security-solution/data_table/common/types/detail_panel.ts +++ b/x-pack/packages/security-solution/data_table/common/types/detail_panel.ts @@ -23,26 +23,7 @@ export type ExpandedEventType = } | EmptyObject; -export type ExpandedHostType = - | { - panelView?: 'hostDetail'; - params?: { - hostName: string; - }; - } - | EmptyObject; - -export type ExpandedNetworkType = - | { - panelView?: 'networkDetail'; - params?: { - ip: string; - flowTarget: FlowTargetSourceDest; - }; - } - | EmptyObject; - -export type ExpandedDetailType = ExpandedEventType | ExpandedHostType | ExpandedNetworkType; +export type ExpandedDetailType = ExpandedEventType; export enum TimelineTabs { query = 'query', diff --git a/x-pack/packages/security-solution/distribution_bar/index.ts b/x-pack/packages/security-solution/distribution_bar/index.ts new file mode 100644 index 0000000000000..b72a2e259552b --- /dev/null +++ b/x-pack/packages/security-solution/distribution_bar/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { DistributionBar } from './src/distribution_bar'; +export type { DistributionBarProps } from './src/distribution_bar'; diff --git a/x-pack/packages/security-solution/distribution_bar/jest.config.js b/x-pack/packages/security-solution/distribution_bar/jest.config.js new file mode 100644 index 0000000000000..efe091d25afdd --- /dev/null +++ b/x-pack/packages/security-solution/distribution_bar/jest.config.js @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +module.exports = { + preset: '@kbn/test', + roots: ['/x-pack/packages/security-solution/distribution_bar'], + rootDir: '../../../..', +}; diff --git a/x-pack/packages/security-solution/distribution_bar/kibana.jsonc b/x-pack/packages/security-solution/distribution_bar/kibana.jsonc new file mode 100644 index 0000000000000..5c984aadba9ca --- /dev/null +++ b/x-pack/packages/security-solution/distribution_bar/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-browser", + "id": "@kbn/security-solution-distribution-bar", + "owner": "@elastic/kibana-cloud-security-posture" +} diff --git a/x-pack/packages/security-solution/distribution_bar/package.json b/x-pack/packages/security-solution/distribution_bar/package.json new file mode 100644 index 0000000000000..767f9a79374b1 --- /dev/null +++ b/x-pack/packages/security-solution/distribution_bar/package.json @@ -0,0 +1,7 @@ +{ + "name": "@kbn/security-solution-distribution-bar", + "private": true, + "version": "1.0.0", + "license": "Elastic License 2.0", + "sideEffects": false +} \ No newline at end of file diff --git a/x-pack/packages/security-solution/distribution_bar/src/distribution_bar.stories.tsx b/x-pack/packages/security-solution/distribution_bar/src/distribution_bar.stories.tsx new file mode 100644 index 0000000000000..d483a60c6041e --- /dev/null +++ b/x-pack/packages/security-solution/distribution_bar/src/distribution_bar.stories.tsx @@ -0,0 +1,73 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { euiThemeVars } from '@kbn/ui-theme'; +import { EuiTitle, EuiSpacer } from '@elastic/eui'; +import { DistributionBar as DistributionBarComponent } from '..'; + +const mockStatsFindings = [ + { + key: 'passed', + count: 90, + color: euiThemeVars.euiColorVis0, + }, + { + key: 'failed', + count: 10, + color: euiThemeVars.euiColorVis9, + }, +]; + +const mockStatsAlerts = [ + { + key: 'low', + count: 30, + color: euiThemeVars.euiColorVis0, + }, + { + key: 'medium', + count: 30, + color: euiThemeVars.euiColorVis5, + }, + { + key: 'high', + count: 10, + color: euiThemeVars.euiColorVis7, + }, + { + key: 'critical', + count: 10, + color: euiThemeVars.euiColorVis9, + }, +]; + +export default { + title: 'DistributionBar', + description: 'Distribution Bar', +}; + +export const DistributionBar = () => { + return [ + +

{'Findings'}

+
, + , + , + , + +

{'Alerts'}

+
, + , + , + , + +

{'Empty state'}

+
, + , + , + ]; +}; diff --git a/x-pack/packages/security-solution/distribution_bar/src/distribution_bar.test.tsx b/x-pack/packages/security-solution/distribution_bar/src/distribution_bar.test.tsx new file mode 100644 index 0000000000000..0a07f1b49e0bb --- /dev/null +++ b/x-pack/packages/security-solution/distribution_bar/src/distribution_bar.test.tsx @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { render } from '@testing-library/react'; +import { DistributionBar } from '..'; + +describe('DistributionBar', () => { + it('should render', () => { + const stats = [ + { + key: 'passed', + count: 90, + color: 'green', + }, + { + key: 'failed', + count: 10, + color: 'red', + }, + ]; + + const { container } = render(); + expect(container).toBeInTheDocument(); + expect(container.querySelectorAll('span').length).toEqual(stats.length); + }); + + it('should render empty bar', () => { + const { container } = render( + + ); + expect(container).toBeInTheDocument(); + expect(container.querySelectorAll('span').length).toEqual(1); + expect( + container.querySelector('[data-test-subj="distribution-bar__emptyBar"]') + ).toBeInTheDocument(); + }); +}); diff --git a/x-pack/packages/security-solution/distribution_bar/src/distribution_bar.tsx b/x-pack/packages/security-solution/distribution_bar/src/distribution_bar.tsx new file mode 100644 index 0000000000000..d6f8ed120c1c9 --- /dev/null +++ b/x-pack/packages/security-solution/distribution_bar/src/distribution_bar.tsx @@ -0,0 +1,75 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { EuiFlexGroup, useEuiTheme } from '@elastic/eui'; +import { css } from '@emotion/react'; + +/** DistributionBar component props */ +export interface DistributionBarProps { + /** distribution data points */ + stats: Array<{ key: string; count: number; color: string }>; + /** data-test-subj used for querying the component in tests */ + ['data-test-subj']?: string; +} + +export interface EmptyBarProps { + ['data-test-subj']?: string; +} + +const styles = { + base: css` + border-radius: 2px; + height: 5px; + `, +}; + +const EmptyBar: React.FC = ({ 'data-test-subj': dataTestSubj }) => { + const { euiTheme } = useEuiTheme(); + + const emptyBarStyle = [ + styles.base, + css` + background-color: ${euiTheme.colors.lightShade}; + flex: 1; + `, + ]; + + return ; +}; + +/** + * Security Solution DistributionBar component. + * Shows visual representation of distribution of stats, such as alerts by criticality or misconfiguration findings by evaluation result. + */ +export const DistributionBar: React.FC = React.memo(function DistributionBar( + props +) { + const { euiTheme } = useEuiTheme(); + const { stats, 'data-test-subj': dataTestSubj } = props; + const parts = stats.map((stat) => { + const partStyle = [ + styles.base, + css` + background-color: ${stat.color}; + flex: ${stat.count}; + `, + ]; + + return ; + }); + + return ( + + {parts.length ? parts : } + + ); +}); diff --git a/x-pack/packages/security-solution/distribution_bar/tsconfig.json b/x-pack/packages/security-solution/distribution_bar/tsconfig.json new file mode 100644 index 0000000000000..b87424ce11016 --- /dev/null +++ b/x-pack/packages/security-solution/distribution_bar/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node", + "react", + "@emotion/react/types/css-prop", + "@testing-library/jest-dom", + "@testing-library/react", + ] + }, + "include": ["**/*.ts", "**/*.tsx"], + "kbn_references": [ + "@kbn/ui-theme", + ], + "exclude": ["target/**/*"] +} 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 05d74f781c434..b757c08a9b238 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 @@ -8478,6 +8478,84 @@ Object { `; exports[`Connector type config checks detect connector type changes for: .sentinelone 6`] = ` +Object { + "flags": Object { + "default": Object { + "special": "deep", + }, + "error": [Function], + "presence": "optional", + }, + "keys": Object { + "taskIds": Object { + "flags": Object { + "error": [Function], + }, + "items": Array [ + Object { + "flags": Object { + "error": [Function], + "presence": "optional", + }, + "rules": Array [ + Object { + "args": Object { + "method": [Function], + }, + "name": "custom", + }, + ], + "type": "string", + }, + ], + "type": "array", + }, + }, + "type": "object", +} +`; + +exports[`Connector type config checks detect connector type changes for: .sentinelone 7`] = ` +Object { + "flags": Object { + "default": Object { + "special": "deep", + }, + "error": [Function], + "presence": "optional", + }, + "keys": Object { + "taskId": Object { + "flags": Object { + "error": [Function], + }, + "metas": Array [ + Object { + "x-oas-min-length": 1, + }, + ], + "rules": Array [ + Object { + "args": Object { + "method": [Function], + }, + "name": "custom", + }, + Object { + "args": Object { + "method": [Function], + }, + "name": "custom", + }, + ], + "type": "string", + }, + }, + "type": "object", +} +`; + +exports[`Connector type config checks detect connector type changes for: .sentinelone 8`] = ` Object { "flags": Object { "default": Object { @@ -14184,7 +14262,7 @@ Object { } `; -exports[`Connector type config checks detect connector type changes for: .sentinelone 7`] = ` +exports[`Connector type config checks detect connector type changes for: .sentinelone 9`] = ` Object { "flags": Object { "default": Object { @@ -19891,7 +19969,7 @@ Object { } `; -exports[`Connector type config checks detect connector type changes for: .sentinelone 8`] = ` +exports[`Connector type config checks detect connector type changes for: .sentinelone 10`] = ` Object { "flags": Object { "default": Object { @@ -25598,7 +25676,7 @@ Object { } `; -exports[`Connector type config checks detect connector type changes for: .sentinelone 9`] = ` +exports[`Connector type config checks detect connector type changes for: .sentinelone 11`] = ` Object { "flags": Object { "default": Object { @@ -26055,7 +26133,7 @@ Object { } `; -exports[`Connector type config checks detect connector type changes for: .sentinelone 10`] = ` +exports[`Connector type config checks detect connector type changes for: .sentinelone 12`] = ` Object { "flags": Object { "default": Object { @@ -26084,7 +26162,7 @@ Object { } `; -exports[`Connector type config checks detect connector type changes for: .sentinelone 11`] = ` +exports[`Connector type config checks detect connector type changes for: .sentinelone 13`] = ` Object { "flags": Object { "default": Object { @@ -26113,7 +26191,7 @@ Object { } `; -exports[`Connector type config checks detect connector type changes for: .sentinelone 12`] = ` +exports[`Connector type config checks detect connector type changes for: .sentinelone 14`] = ` Object { "flags": Object { "default": Object { diff --git a/x-pack/plugins/actions/server/plugin.ts b/x-pack/plugins/actions/server/plugin.ts index 3112124850bfb..2f83f945ba3ef 100644 --- a/x-pack/plugins/actions/server/plugin.ts +++ b/x-pack/plugins/actions/server/plugin.ts @@ -32,7 +32,7 @@ import { } from '@kbn/task-manager-plugin/server'; import { LicensingPluginSetup, LicensingPluginStart } from '@kbn/licensing-plugin/server'; import { SpacesPluginStart, SpacesPluginSetup } from '@kbn/spaces-plugin/server'; -import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { SecurityPluginSetup, SecurityPluginStart } from '@kbn/security-plugin/server'; import { IEventLogClientService, diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/analysis_handlers/significant_items_handler.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/analysis_handlers/significant_items_handler.ts index 197cc17b77a91..16c2d9f9212a5 100644 --- a/x-pack/plugins/aiops/server/routes/log_rate_analysis/analysis_handlers/significant_items_handler.ts +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/analysis_handlers/significant_items_handler.ts @@ -6,6 +6,7 @@ */ import { queue } from 'async'; +import { chunk } from 'lodash'; import { SIGNIFICANT_ITEM_TYPE, type SignificantItem } from '@kbn/ml-agg-utils'; import { i18n } from '@kbn/i18n'; @@ -17,10 +18,15 @@ import type { AiopsLogRateAnalysisSchema, AiopsLogRateAnalysisApiVersion as ApiVersion, } from '@kbn/aiops-log-rate-analysis/api/schema'; +import type { QueueFieldCandidate } from '@kbn/aiops-log-rate-analysis/queue_field_candidates'; +import { + isKeywordFieldCandidates, + isTextFieldCandidates, + QUEUE_CHUNKING_SIZE, +} from '@kbn/aiops-log-rate-analysis/queue_field_candidates'; import { isRequestAbortedError } from '@kbn/aiops-common/is_request_aborted_error'; import { fetchSignificantCategories } from '@kbn/aiops-log-rate-analysis/queries/fetch_significant_categories'; import { fetchSignificantTermPValues } from '@kbn/aiops-log-rate-analysis/queries/fetch_significant_term_p_values'; -import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { LOADED_FIELD_CANDIDATES, @@ -29,20 +35,6 @@ import { } from '../response_stream_utils/constants'; import type { ResponseStreamFetchOptions } from '../response_stream_factory'; -interface FieldCandidate { - fieldCandidate: string; -} -const isFieldCandidate = (d: unknown): d is FieldCandidate => - isPopulatedObject(d, ['fieldCandidate']); - -interface TextFieldCandidate { - textFieldCandidate: string; -} -const isTextFieldCandidate = (d: unknown): d is FieldCandidate => - isPopulatedObject(d, ['textFieldCandidate']); - -type Candidate = FieldCandidate | TextFieldCandidate; - export const significantItemsHandlerFactory = ({ abortSignal, @@ -82,8 +74,6 @@ export const significantItemsHandlerFactory = ) ?? []) ); - const fieldsToSample = new Set(); - let remainingFieldCandidates: string[]; let loadingStepSizePValues = PROGRESS_STEP_P_VALUES; @@ -104,9 +94,12 @@ export const significantItemsHandlerFactory = const loadingStep = (1 / (fieldCandidatesCount + textFieldCandidatesCount)) * loadingStepSizePValues; - const pValuesQueue = queue(async function (payload: Candidate) { - if (isFieldCandidate(payload)) { - const { fieldCandidate } = payload; + const pValuesQueue = queue(async function (payload: QueueFieldCandidate) { + let queueItemLoadingStep = 0; + + if (isKeywordFieldCandidates(payload)) { + const { keywordFieldCandidates: fieldNames } = payload; + queueItemLoadingStep = loadingStep * fieldNames.length; let pValues: Awaited>; try { @@ -117,34 +110,30 @@ export const significantItemsHandlerFactory = emitError: responseStream.pushError, arguments: { ...requestBody, - fieldNames: [fieldCandidate], + fieldNames, sampleProbability: stateHandler.sampleProbability(), }, }); } catch (e) { if (!isRequestAbortedError(e)) { logger.error( - `Failed to fetch p-values for '${fieldCandidate}', got: \n${e.toString()}` + `Failed to fetch p-values for ${fieldNames.join()}, got: \n${e.toString()}` ); - responseStream.pushError(`Failed to fetch p-values for '${fieldCandidate}'.`); + responseStream.pushError(`Failed to fetch p-values for ${fieldNames.join()}.`); } return; } - remainingFieldCandidates = remainingFieldCandidates.filter((d) => d !== fieldCandidate); + remainingFieldCandidates = remainingFieldCandidates.filter((d) => !fieldNames.includes(d)); if (pValues.length > 0) { - pValues.forEach((d) => { - fieldsToSample.add(d.fieldName); - }); significantTerms.push(...pValues); - responseStream.push(addSignificantItems(pValues)); - fieldValuePairsCount += pValues.length; } - } else if (isTextFieldCandidate(payload)) { - const { textFieldCandidate } = payload; + } else if (isTextFieldCandidates(payload)) { + const { textFieldCandidates: fieldNames } = payload; + queueItemLoadingStep = loadingStep * fieldNames.length; const significantCategoriesForField = await fetchSignificantCategories({ esClient, @@ -153,7 +142,7 @@ export const significantItemsHandlerFactory = abortSignal, arguments: { ...requestBody, - fieldNames: [textFieldCandidate], + fieldNames, sampleProbability: stateHandler.sampleProbability(), }, }); @@ -165,7 +154,7 @@ export const significantItemsHandlerFactory = } } - stateHandler.loaded(loadingStep, false); + stateHandler.loaded(queueItemLoadingStep, false); responseStream.push( updateLoadingState({ @@ -186,10 +175,14 @@ export const significantItemsHandlerFactory = ); }, MAX_CONCURRENT_QUERIES); + // This chunks keyword and text field candidates, then passes them on + // to the async queue for processing. Each chunk will be part of a single + // query using multiple aggs for each candidate. For many candidates, + // on top of that the async queue will process multiple queries concurrently. pValuesQueue.push( [ - ...textFieldCandidates.map((d) => ({ textFieldCandidate: d })), - ...fieldCandidates.map((d) => ({ fieldCandidate: d })), + ...chunk(textFieldCandidates, QUEUE_CHUNKING_SIZE).map((d) => ({ textFieldCandidates: d })), + ...chunk(fieldCandidates, QUEUE_CHUNKING_SIZE).map((d) => ({ keywordFieldCandidates: d })), ], (err) => { if (err) { diff --git a/x-pack/plugins/alerting/server/alerting_authorization_client_factory.ts b/x-pack/plugins/alerting/server/alerting_authorization_client_factory.ts index b0830a7127a38..ca366a6cee0e4 100644 --- a/x-pack/plugins/alerting/server/alerting_authorization_client_factory.ts +++ b/x-pack/plugins/alerting/server/alerting_authorization_client_factory.ts @@ -7,7 +7,7 @@ import { KibanaRequest } from '@kbn/core/server'; import { SecurityPluginSetup, SecurityPluginStart } from '@kbn/security-plugin/server'; -import { PluginStartContract as FeaturesPluginStart } from '@kbn/features-plugin/server'; +import { FeaturesPluginStart } from '@kbn/features-plugin/server'; import { Space } from '@kbn/spaces-plugin/server'; import { AlertingAuthorization } from './authorization/alerting_authorization'; import { RuleTypeRegistry } from './types'; diff --git a/x-pack/plugins/alerting/server/authorization/alerting_authorization.test.ts b/x-pack/plugins/alerting/server/authorization/alerting_authorization.test.ts index da2774e263b58..569fff83eaefe 100644 --- a/x-pack/plugins/alerting/server/authorization/alerting_authorization.test.ts +++ b/x-pack/plugins/alerting/server/authorization/alerting_authorization.test.ts @@ -10,7 +10,7 @@ import { KibanaRequest } from '@kbn/core/server'; import { ruleTypeRegistryMock } from '../rule_type_registry.mock'; import { securityMock } from '@kbn/security-plugin/server/mocks'; import { - PluginStartContract as FeaturesStartContract, + FeaturesPluginStart as FeaturesStartContract, KibanaFeature, } from '@kbn/features-plugin/server'; import { featuresPluginMock } from '@kbn/features-plugin/server/mocks'; diff --git a/x-pack/plugins/alerting/server/authorization/alerting_authorization.ts b/x-pack/plugins/alerting/server/authorization/alerting_authorization.ts index 2102ff245b9f8..0fb53c1eab0a1 100644 --- a/x-pack/plugins/alerting/server/authorization/alerting_authorization.ts +++ b/x-pack/plugins/alerting/server/authorization/alerting_authorization.ts @@ -11,7 +11,7 @@ import { KibanaRequest } from '@kbn/core/server'; import { JsonObject } from '@kbn/utility-types'; import { KueryNode } from '@kbn/es-query'; import { SecurityPluginSetup } from '@kbn/security-plugin/server'; -import { PluginStartContract as FeaturesPluginStart } from '@kbn/features-plugin/server'; +import { FeaturesPluginStart } from '@kbn/features-plugin/server'; import { Space } from '@kbn/spaces-plugin/server'; import { RegistryRuleType } from '../rule_type_registry'; import { ALERTING_FEATURE_ID, RuleTypeRegistry } from '../types'; diff --git a/x-pack/plugins/alerting/server/plugin.ts b/x-pack/plugins/alerting/server/plugin.ts index 3c996c532acf2..d310c6e3567c3 100644 --- a/x-pack/plugins/alerting/server/plugin.ts +++ b/x-pack/plugins/alerting/server/plugin.ts @@ -48,10 +48,7 @@ import { IEventLogService, IEventLogClientService, } from '@kbn/event-log-plugin/server'; -import { - PluginStartContract as FeaturesPluginStart, - PluginSetupContract as FeaturesPluginSetup, -} from '@kbn/features-plugin/server'; +import { FeaturesPluginStart, FeaturesPluginSetup } from '@kbn/features-plugin/server'; import type { PluginSetup as UnifiedSearchServerPluginSetup } from '@kbn/unified-search-plugin/server'; import { PluginStart as DataPluginStart } from '@kbn/data-plugin/server'; import { MonitoringCollectionSetup } from '@kbn/monitoring-collection-plugin/server'; diff --git a/x-pack/plugins/canvas/server/plugin.ts b/x-pack/plugins/canvas/server/plugin.ts index 16e39eb46ee34..36a6fbbd0e3e2 100644 --- a/x-pack/plugins/canvas/server/plugin.ts +++ b/x-pack/plugins/canvas/server/plugin.ts @@ -15,7 +15,7 @@ import { BfetchServerSetup } from '@kbn/bfetch-plugin/server'; import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server'; import { HomeServerPluginSetup } from '@kbn/home-plugin/server'; import { EmbeddableSetup } from '@kbn/embeddable-plugin/server'; -import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { ReportingServerPluginSetup } from '@kbn/reporting-server'; import { getCanvasFeature } from './feature'; import { initRoutes } from './routes'; diff --git a/x-pack/plugins/cases/public/components/user_actions/property_actions/user_comment_property_actions.test.tsx b/x-pack/plugins/cases/public/components/user_actions/property_actions/user_comment_property_actions.test.tsx index 8fc3b0cb8adcb..c24d26fa3b283 100644 --- a/x-pack/plugins/cases/public/components/user_actions/property_actions/user_comment_property_actions.test.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/property_actions/user_comment_property_actions.test.tsx @@ -17,7 +17,8 @@ import { import { UserCommentPropertyActions } from './user_comment_property_actions'; import { waitFor } from '@testing-library/react'; -describe('UserCommentPropertyActions', () => { +// FLAKY: https://github.com/elastic/kibana/issues/175310 +describe.skip('UserCommentPropertyActions', () => { let appMock: AppMockRenderer; const props = { diff --git a/x-pack/plugins/cases/server/authorization/authorization.test.ts b/x-pack/plugins/cases/server/authorization/authorization.test.ts index d02b8f011cf75..6385bc03813a0 100644 --- a/x-pack/plugins/cases/server/authorization/authorization.test.ts +++ b/x-pack/plugins/cases/server/authorization/authorization.test.ts @@ -16,7 +16,7 @@ import type { KibanaRequest } from '@kbn/core/server'; import type { KibanaFeature } from '@kbn/features-plugin/common'; import type { AuditLogger, SecurityPluginStart } from '@kbn/security-plugin/server'; import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; -import type { PluginStartContract as FeaturesPluginStart } from '@kbn/features-plugin/server'; +import type { FeaturesPluginStart } from '@kbn/features-plugin/server'; const createSpacesDisabledFeaturesMock = (disabledFeatures: string[] = []) => { const spacesStart: jest.Mocked = spacesMock.createStart(); diff --git a/x-pack/plugins/cases/server/authorization/authorization.ts b/x-pack/plugins/cases/server/authorization/authorization.ts index c67b69c4f305f..ed255a5df18aa 100644 --- a/x-pack/plugins/cases/server/authorization/authorization.ts +++ b/x-pack/plugins/cases/server/authorization/authorization.ts @@ -9,7 +9,7 @@ import type { SavedObject } from '@kbn/core-saved-objects-server'; import type { KibanaRequest, Logger } from '@kbn/core/server'; import Boom from '@hapi/boom'; import type { SecurityPluginStart } from '@kbn/security-plugin/server'; -import type { PluginStartContract as FeaturesPluginStart } from '@kbn/features-plugin/server'; +import type { FeaturesPluginStart } from '@kbn/features-plugin/server'; import type { Space, SpacesPluginStart } from '@kbn/spaces-plugin/server'; import type { AuthFilterHelpers, OwnerEntity } from './types'; import { getOwnersFilter, groupByAuthorization } from './utils'; diff --git a/x-pack/plugins/cases/server/client/factory.ts b/x-pack/plugins/cases/server/client/factory.ts index 865ee2ff3b684..fde1d82cf46cb 100644 --- a/x-pack/plugins/cases/server/client/factory.ts +++ b/x-pack/plugins/cases/server/client/factory.ts @@ -21,7 +21,7 @@ import type { SecurityPluginSetup, SecurityPluginStart, } from '@kbn/security-plugin/server'; -import type { PluginStartContract as FeaturesPluginStart } from '@kbn/features-plugin/server'; +import type { FeaturesPluginStart } from '@kbn/features-plugin/server'; import type { PluginStartContract as ActionsPluginStart } from '@kbn/actions-plugin/server'; import type { LensServerPluginSetup } from '@kbn/lens-plugin/server'; import type { SpacesPluginStart } from '@kbn/spaces-plugin/server'; diff --git a/x-pack/plugins/cases/server/types.ts b/x-pack/plugins/cases/server/types.ts index f404f7346144c..0153083337cfa 100644 --- a/x-pack/plugins/cases/server/types.ts +++ b/x-pack/plugins/cases/server/types.ts @@ -19,10 +19,7 @@ import type { PluginStartContract as ActionsPluginStart, } from '@kbn/actions-plugin/server'; import type { SpacesPluginSetup, SpacesPluginStart } from '@kbn/spaces-plugin/server'; -import type { - PluginStartContract as FeaturesPluginStart, - PluginSetupContract as FeaturesPluginSetup, -} from '@kbn/features-plugin/server'; +import type { FeaturesPluginStart, FeaturesPluginSetup } from '@kbn/features-plugin/server'; import type { LensServerPluginSetup } from '@kbn/lens-plugin/server'; import type { TaskManagerSetupContract, diff --git a/x-pack/plugins/cloud_integrations/cloud_data_migration/server/types.ts b/x-pack/plugins/cloud_integrations/cloud_data_migration/server/types.ts index 7ae5c3b36b2c2..6cb7c1c129d73 100644 --- a/x-pack/plugins/cloud_integrations/cloud_data_migration/server/types.ts +++ b/x-pack/plugins/cloud_integrations/cloud_data_migration/server/types.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; export interface Dependencies { features: FeaturesPluginSetup; diff --git a/x-pack/plugins/cloud_integrations/cloud_experiments/common/constants.ts b/x-pack/plugins/cloud_integrations/cloud_experiments/common/constants.ts index 19287abf2e417..3615d1055a0b1 100644 --- a/x-pack/plugins/cloud_integrations/cloud_experiments/common/constants.ts +++ b/x-pack/plugins/cloud_integrations/cloud_experiments/common/constants.ts @@ -21,13 +21,6 @@ export enum FEATURE_FLAG_NAMES { * It resolves the URL that the button "Add Integrations" will point to. */ 'security-solutions.add-integrations-url' = 'security-solutions.add-integrations-url', - /** - * Used in the Security Solutions guided onboarding tour. - * Returns JSON corresponding to the tour guide config as - * defined by type { GuideConfig } from '@kbn/guided-onboarding'; - */ - 'security-solutions.guided-onboarding-content' = 'security-solutions.guided-onboarding-content', - /** * Used in cloud chat plugin to enable/disable the chat. * The expectation that the chat is enabled by default and the flag is used as a runtime kill switch. diff --git a/x-pack/plugins/cross_cluster_replication/server/types.ts b/x-pack/plugins/cross_cluster_replication/server/types.ts index 6752bf397203b..72fb1e40a58ff 100644 --- a/x-pack/plugins/cross_cluster_replication/server/types.ts +++ b/x-pack/plugins/cross_cluster_replication/server/types.ts @@ -6,7 +6,7 @@ */ import { IRouter } from '@kbn/core/server'; -import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { LicensingPluginSetup, LicensingPluginStart } from '@kbn/licensing-plugin/server'; import { IndexManagementPluginSetup } from '@kbn/index-management-plugin/server'; import { RemoteClustersPluginSetup } from '@kbn/remote-clusters-plugin/server'; diff --git a/x-pack/plugins/data_quality/server/types.ts b/x-pack/plugins/data_quality/server/types.ts index 7ae5c3b36b2c2..6cb7c1c129d73 100644 --- a/x-pack/plugins/data_quality/server/types.ts +++ b/x-pack/plugins/data_quality/server/types.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; export interface Dependencies { features: FeaturesPluginSetup; diff --git a/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/data_visualizer_stats_table.tsx b/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/data_visualizer_stats_table.tsx index 74083dec0e5da..811d69b6bfeb3 100644 --- a/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/data_visualizer_stats_table.tsx +++ b/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/data_visualizer_stats_table.tsx @@ -62,6 +62,7 @@ interface DataVisualizerTableProps { totalCount?: number; overallStatsRunning: boolean; renderFieldName?: FieldStatisticTableEmbeddableProps['renderFieldName']; + error?: Error | string; } export const DataVisualizerTable = ({ @@ -76,6 +77,7 @@ export const DataVisualizerTable = ({ totalCount, overallStatsRunning, renderFieldName, + error, }: DataVisualizerTableProps) => { const { euiTheme } = useEuiTheme(); @@ -461,6 +463,21 @@ export const DataVisualizerTable = ({ }, }, }); + + const message = useMemo(() => { + if (!overallStatsRunning && error) { + return i18n.translate('xpack.dataVisualizer.dataGrid.errorMessage', { + defaultMessage: 'An error occured fetching field statistics', + }); + } + + if (loading) { + return i18n.translate('xpack.dataVisualizer.dataGrid.searchingMessage', { + defaultMessage: 'Searching', + }); + } + return undefined; + }, [error, loading, overallStatsRunning]); return ( {(resizeRef) => ( @@ -470,13 +487,7 @@ export const DataVisualizerTable = ({ data-shared-item="" // TODO: Remove data-shared-item as part of https://github.com/elastic/kibana/issues/179376 > - message={ - loading - ? i18n.translate('xpack.dataVisualizer.dataGrid.searchingMessage', { - defaultMessage: 'Searching', - }) - : undefined - } + message={message} css={dvTableCss} items={items} itemId={FIELD_NAME} diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/index_data_visualizer_view/index_data_visualizer_esql.tsx b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/index_data_visualizer_view/index_data_visualizer_esql.tsx index fd65ed3c7dfa6..686dcffdc9f76 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/index_data_visualizer_view/index_data_visualizer_esql.tsx +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/index_data_visualizer_view/index_data_visualizer_esql.tsx @@ -48,6 +48,7 @@ import type { } from '../../embeddables/grid_embeddable/types'; import type { ESQLQuery } from '../../search_strategy/requests/esql_utils'; import { isESQLQuery } from '../../search_strategy/requests/esql_utils'; +import { FieldStatsComponentType } from '../../constants/field_stats_component_type'; export interface IndexDataVisualizerESQLProps { getAdditionalLinks?: GetAdditionalLinks; @@ -115,7 +116,7 @@ export const IndexDataVisualizerESQL: FC = (dataVi if (!indexPattern) return; const dv = await getOrCreateDataViewByIndexPattern( data.dataViews, - indexPattern, + query.esql, currentDataView ); @@ -144,7 +145,7 @@ export const IndexDataVisualizerESQL: FC = (dataVi sessionId: undefined, visibleFieldNames: undefined, allowEditDataView: true, - id: 'esql_data_visualizer', + id: FieldStatsComponentType.EsqlDataVisualizer, indexPattern, esql: true, }; @@ -265,7 +266,7 @@ export const IndexDataVisualizerESQL: FC = (dataVi onTextLangQuerySubmit={onTextLangQuerySubmit} expandCodeEditor={expandCodeEditor} isCodeEditorExpanded={true} - detectTimestamp={true} + detectedTimestamp={currentDataView?.timeFieldName} hideMinimizeButton={true} hideRunQueryText={false} isLoading={queryHistoryStatus ?? false} diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/constants/field_stats_component_type.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/constants/field_stats_component_type.ts new file mode 100644 index 0000000000000..84b67909e99ed --- /dev/null +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/constants/field_stats_component_type.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export enum FieldStatsComponentType { + EsqlDataVisualizer = 'esql_data_visualizer', + IndexDataVisualizer = 'index_data_visualizer', + DashboardEmbeddable = 'dashboard_embeddable', + DiscoverEmbeddable = 'discover_embeddable', +} diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/embeddables/field_stats/field_stats_factory.tsx b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/embeddables/field_stats/field_stats_factory.tsx index 8e800d5d61767..d644779ba0a87 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/embeddables/field_stats/field_stats_factory.tsx +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/embeddables/field_stats/field_stats_factory.tsx @@ -43,7 +43,7 @@ import { css } from '@emotion/react'; import type { ActionExecutionContext } from '@kbn/ui-actions-plugin/public'; import type { Filter } from '@kbn/es-query'; import { FilterStateStore } from '@kbn/es-query'; -import { getESQLAdHocDataview, getIndexPatternFromESQLQuery } from '@kbn/esql-utils'; +import { getESQLAdHocDataview } from '@kbn/esql-utils'; import { ACTION_GLOBAL_APPLY_FILTER } from '@kbn/unified-search-plugin/public'; import type { DataVisualizerTableState } from '../../../../../common/types'; import type { DataVisualizerPluginStart } from '../../../../plugin'; @@ -54,6 +54,7 @@ import { initializeFieldStatsControls } from './initialize_field_stats_controls' import type { DataVisualizerStartDependencies } from '../../../common/types/data_visualizer_plugin'; import type { FieldStatisticsTableEmbeddableApi } from './types'; import { isESQLQuery } from '../../search_strategy/requests/esql_utils'; +import { FieldStatsComponentType } from '../../constants/field_stats_component_type'; export interface EmbeddableFieldStatsChartStartServices { data: DataPublicPluginStart; @@ -163,10 +164,7 @@ export const getFieldStatsChartEmbeddableFactory = ( let initialDataView: DataView[] | undefined; try { const dataView = isESQLQuery(state.query) - ? await getESQLAdHocDataview( - getIndexPatternFromESQLQuery(state.query.esql), - deps.data.dataViews - ) + ? await getESQLAdHocDataview(state.query.esql, deps.data.dataViews) : await deps.data.dataViews.get(validDataViewId); initialDataView = [dataView]; } catch (error) { @@ -367,6 +365,7 @@ export const getFieldStatsChartEmbeddableFactory = ( return ( = ({ }, [dataViewId, viewType, esqlQuery.esql, isEsqlMode]); const onESQLQuerySubmit = useCallback( async (query: AggregateQuery, abortController: AbortController) => { - const adhocDataView = await getESQLAdHocDataview( - getIndexPatternFromESQLQuery(query.esql), - dataViews - ); + const adhocDataView = await getESQLAdHocDataview(query.esql, dataViews); if (adhocDataView && adhocDataView.id) { setDataViewId(adhocDataView.id); } diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/embeddables/field_stats/resolve_field_stats_embeddable_input.tsx b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/embeddables/field_stats/resolve_field_stats_embeddable_input.tsx index 893e77c12e80b..f23a83fd42388 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/embeddables/field_stats/resolve_field_stats_embeddable_input.tsx +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/embeddables/field_stats/resolve_field_stats_embeddable_input.tsx @@ -9,7 +9,6 @@ import { tracksOverlays } from '@kbn/presentation-containers'; import { toMountPoint } from '@kbn/react-kibana-mount'; import React from 'react'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; -import { getIndexPatternFromESQLQuery } from '@kbn/esql-utils'; import { isDefined } from '@kbn/ml-is-defined'; import { FieldStatisticsInitializer } from './field_stats_initializer'; import type { DataVisualizerStartDependencies } from '../../../common/types/data_visualizer_plugin'; @@ -53,10 +52,9 @@ export async function resolveEmbeddableFieldStatsUserInput( const update = async (nextUpdate: FieldStatsInitialState) => { const esqlQuery = nextUpdate?.query?.esql; if (isDefined(esqlQuery)) { - const indexPatternFromQuery = getIndexPatternFromESQLQuery(esqlQuery); const dv = await getOrCreateDataViewByIndexPattern( pluginStart.data.dataViews, - indexPatternFromQuery, + esqlQuery, undefined ); if (dv?.id && nextUpdate.dataViewId !== dv.id) { diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/embeddables/grid_embeddable/embeddable_esql_field_stats_table.tsx b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/embeddables/grid_embeddable/embeddable_esql_field_stats_table.tsx index 3cf282e3da1a2..a548acbe6c71c 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/embeddables/grid_embeddable/embeddable_esql_field_stats_table.tsx +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/embeddables/grid_embeddable/embeddable_esql_field_stats_table.tsx @@ -79,6 +79,7 @@ const EmbeddableESQLFieldStatsTableWrapper = React.memo( onChange={onTableUpdate} loading={progress < 100} overallStatsRunning={overallStatsProgress.isRunning} + error={overallStatsProgress.error} /> ); } diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/embeddables/grid_embeddable/field_stats_wrapper.tsx b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/embeddables/grid_embeddable/field_stats_wrapper.tsx index 9899c7f9251e0..03dbb9c7af8c8 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/embeddables/grid_embeddable/field_stats_wrapper.tsx +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/embeddables/grid_embeddable/field_stats_wrapper.tsx @@ -43,6 +43,7 @@ const FieldStatisticsWrapperContent = (props: FieldStatisticTableEmbeddableProps if (isESQLFieldStatisticTableEmbeddableState(props)) { return ( { ({ columns: allColumns, filter, limit, + timeRange, }: { searchQuery?: AggregateQuery; columns?: T[]; filter?: QueryDslQueryContainer; limit: number; + timeRange?: TimeRange; }) => { const [fieldStats, setFieldStats] = useState>(); @@ -93,6 +95,7 @@ export const useESQLFieldStatsData = ({ filter, runRequest, esqlBaseQuery, + timeRange, }).then(addToProcessedFieldStats); // GETTING STATS FOR KEYWORD FIELDS @@ -103,6 +106,7 @@ export const useESQLFieldStatsData = ({ filter, runRequest, esqlBaseQuery, + timeRange, }).then(addToProcessedFieldStats); // GETTING STATS FOR BOOLEAN FIELDS @@ -111,6 +115,7 @@ export const useESQLFieldStatsData = ({ filter, runRequest, esqlBaseQuery, + timeRange, }).then(addToProcessedFieldStats); // GETTING STATS FOR DATE FIELDS @@ -119,6 +124,7 @@ export const useESQLFieldStatsData = ({ filter, runRequest, esqlBaseQuery, + timeRange, }).then(addToProcessedFieldStats); } setFetchState({ diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/hooks/esql/use_esql_overall_stats_data.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/hooks/esql/use_esql_overall_stats_data.ts index 4634c1991de8b..84567075db046 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/hooks/esql/use_esql_overall_stats_data.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/hooks/esql/use_esql_overall_stats_data.ts @@ -7,8 +7,9 @@ import { ESQL_ASYNC_SEARCH_STRATEGY, KBN_FIELD_TYPES } from '@kbn/data-plugin/common'; import type { QueryDslQueryContainer } from '@kbn/data-views-plugin/common/types'; -import type { AggregateQuery } from '@kbn/es-query'; +import type { AggregateQuery, TimeRange } from '@kbn/es-query'; import { i18n } from '@kbn/i18n'; +import { getEarliestLatestParams } from '@kbn/esql-utils'; import { useCallback, useEffect, useMemo, useReducer, useRef, useState } from 'react'; import { type UseCancellableSearch, useCancellableSearch } from '@kbn/ml-cancellable-search'; import type { estypes } from '@elastic/elasticsearch'; @@ -69,7 +70,8 @@ const getESQLDocumentCountStats = async ( timeFieldName?: string, intervalMs?: number, searchOptions?: ISearchOptions, - onError?: HandleErrorCallback + onError?: HandleErrorCallback, + timeRange?: TimeRange ): Promise<{ documentCountStats?: DocumentCountStats; totalCount: number; request?: object }> => { if (!isESQLQuery(query)) { throw Error( @@ -81,6 +83,7 @@ const getESQLDocumentCountStats = async ( const esqlBaseQuery = query.esql; let earliestMs = Infinity; let latestMs = -Infinity; + const namedParams = getEarliestLatestParams(esqlBaseQuery, timeRange); if (timeFieldName) { const aggQuery = appendToESQLQuery( @@ -95,6 +98,7 @@ const getESQLDocumentCountStats = async ( params: { query: aggQuery, ...(filter ? { filter } : {}), + ...(namedParams.length ? { params: namedParams } : {}), }, }; try { @@ -143,6 +147,7 @@ const getESQLDocumentCountStats = async ( params: { query: appendToESQLQuery(esqlBaseQuery, ' | STATS _count_ = COUNT(*) | LIMIT 1'), ...(filter ? { filter } : {}), + ...(namedParams.length ? { params: namedParams } : {}), }, }; try { @@ -159,7 +164,6 @@ const getESQLDocumentCountStats = async ( handleError({ request, error, - onError, title: i18n.translate('xpack.dataVisualizer.esql.docCountNoneTimeseriesError', { defaultMessage: `Error getting total count for ES|QL data:`, }), @@ -193,6 +197,7 @@ const fieldStatsErrorTitle = i18n.translate( export const useESQLOverallStatsData = ( fieldStatsRequest: | { + id?: string; earliest: number | undefined; latest: number | undefined; aggInterval: TimeBucketsInterval; @@ -204,6 +209,7 @@ export const useESQLOverallStatsData = ( limit: number; filter?: QueryDslQueryContainer; totalCount?: number; + timeRange?: TimeRange; } | undefined ) => { @@ -214,7 +220,10 @@ export const useESQLOverallStatsData = ( }, } = useDataVisualizerKibana(); + const previousExecutionTs = useRef(undefined); const previousDocCountRequest = useRef(''); + const previousError = useRef(); + const { runRequest, cancelRequest } = useCancellableSearch(data); const [tableData, setTableData] = useReducer(getReducer(), getInitialData()); @@ -224,33 +233,53 @@ export const useESQLOverallStatsData = ( getInitialProgress() ); const onError = useCallback( - (error, title?: string) => + (error: Error, title?: string) => { + // If a previous error already occured, no need to show the toast again + if (previousError.current) { + return; + } + previousError.current = error; toasts.addError(error, { title: title ?? fieldStatsErrorTitle, - }), + }); + }, [toasts] ); const startFetch = useCallback( async function fetchOverallStats() { try { - cancelRequest(); + if (!fieldStatsRequest || fieldStatsRequest.lastRefresh === 0) { + return; + } - if (!fieldStatsRequest) { + // Prevent requests from being called again when user clicks refresh consecutively too fast + // or when Discover forces a refresh right after query or filter changes + if ( + fieldStatsRequest.id === undefined && + previousExecutionTs.current !== undefined && + (fieldStatsRequest.lastRefresh === previousExecutionTs.current || + fieldStatsRequest.lastRefresh - previousExecutionTs.current < 800) + ) { return; } + previousExecutionTs.current = fieldStatsRequest.lastRefresh; + + cancelRequest(); + setOverallStatsProgress({ ...getInitialProgress(), isRunning: true, error: undefined, }); - + previousError.current = undefined; const { searchQuery, intervalMs, filter: filter, limit, totalCount: knownTotalCount, + timeRange, } = fieldStatsRequest; if (!isESQLQuery(searchQuery)) { @@ -269,12 +298,14 @@ export const useESQLOverallStatsData = ( // And use this one query to // 1) identify populated/empty fields // 2) gather examples for populated text fields + const namedParams = getEarliestLatestParams(esqlBaseQuery, timeRange); const columnsResp = (await runRequest( { params: { // Doing this to match with the default limit query: getESQLWithSafeLimit(esqlBaseQuery, ESQL_SAFE_LIMIT), ...(filter ? { filter } : {}), + ...(namedParams.length ? { params: namedParams } : {}), dropNullColumns: true, }, }, @@ -340,7 +371,8 @@ export const useESQLOverallStatsData = ( timeFieldName, intervalInMs, undefined, - onError + onError, + timeRange ); totalCount = results.totalCount; @@ -424,6 +456,7 @@ export const useESQLOverallStatsData = ( limitSize: limit, totalCount, onError, + timeRange, }); if (!stats) return; stats.aggregatableNotExistsFields = aggregatableNotExistsFields; @@ -453,6 +486,11 @@ export const useESQLOverallStatsData = ( setTableData({ exampleDocs }); } } catch (error) { + setOverallStatsProgress({ + loaded: 100, + isRunning: false, + error, + }); setQueryHistoryStatus(false); // If error already handled in sub functions, no need to propogate if (error.name !== 'AbortError' && error.handled !== true) { diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/hooks/use_field_stats.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/hooks/use_field_stats.ts index 563de0ef235a2..2b93f7a56eb92 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/hooks/use_field_stats.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/hooks/use_field_stats.ts @@ -195,11 +195,13 @@ export function useFieldStatsSearchStrategy( .filter((obs) => obs !== undefined) as Array>; const onError = (error: any) => { - toasts.addError(error, { - title: i18n.translate('xpack.dataVisualizer.index.errorFetchingFieldStatisticsMessage', { + // eslint-disable-next-line no-console + console.error( + i18n.translate('xpack.dataVisualizer.index.errorFetchingFieldStatisticsMessage', { defaultMessage: 'Error fetching field statistics', }), - }); + error + ); setFetchState({ isRunning: false, error, diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_boolean_field_stats.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_boolean_field_stats.ts index a91e42e2f8213..8538c78f93a5a 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_boolean_field_stats.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_boolean_field_stats.ts @@ -4,12 +4,12 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - +import type { TimeRange } from '@kbn/es-query'; import type { UseCancellableSearch } from '@kbn/ml-cancellable-search'; import type { QueryDslQueryContainer } from '@kbn/data-views-plugin/common/types'; import { ESQL_ASYNC_SEARCH_STRATEGY } from '@kbn/data-plugin/common'; import pLimit from 'p-limit'; -import { appendToESQLQuery } from '@kbn/esql-utils'; +import { appendToESQLQuery, getEarliestLatestParams } from '@kbn/esql-utils'; import type { Column } from '../../hooks/esql/use_esql_overall_stats_data'; import { getSafeESQLName } from '../requests/esql_utils'; import { isFulfilled, isRejected } from '../../../common/util/promise_all_settled_utils'; @@ -22,6 +22,7 @@ interface Params { columns: Column[]; esqlBaseQuery: string; filter?: QueryDslQueryContainer; + timeRange?: TimeRange; } export const getESQLBooleanFieldStats = async ({ @@ -29,9 +30,10 @@ export const getESQLBooleanFieldStats = async ({ columns, esqlBaseQuery, filter, + timeRange, }: Params): Promise> => { const limiter = pLimit(MAX_CONCURRENT_REQUESTS); - + const namedParams = getEarliestLatestParams(esqlBaseQuery, timeRange); const booleanFields = columns .filter((f) => f.secondaryType === 'boolean') .map((field) => { @@ -49,6 +51,7 @@ export const getESQLBooleanFieldStats = async ({ params: { query, ...(filter ? { filter } : {}), + ...(namedParams.length ? { params: namedParams } : {}), }, }, }; diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_count_and_cardinality.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_count_and_cardinality.ts index f10af0b74ca27..35ff176acec13 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_count_and_cardinality.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_count_and_cardinality.ts @@ -8,8 +8,9 @@ import { ESQL_ASYNC_SEARCH_STRATEGY } from '@kbn/data-plugin/common'; import pLimit from 'p-limit'; import { chunk } from 'lodash'; import { isDefined } from '@kbn/ml-is-defined'; +import type { TimeRange } from '@kbn/es-query'; import type { ESQLSearchResponse } from '@kbn/es-types'; -import { appendToESQLQuery } from '@kbn/esql-utils'; +import { appendToESQLQuery, getEarliestLatestParams } from '@kbn/esql-utils'; import type { UseCancellableSearch } from '@kbn/ml-cancellable-search'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { i18n } from '@kbn/i18n'; @@ -33,6 +34,7 @@ const getESQLOverallStatsInChunk = async ({ limitSize, totalCount, onError, + timeRange, }: { runRequest: UseCancellableSearch['runRequest']; fields: Field[]; @@ -41,6 +43,7 @@ const getESQLOverallStatsInChunk = async ({ limitSize: number; totalCount: number; onError?: HandleErrorCallback; + timeRange?: TimeRange; }) => { if (fields.length > 0) { const aggToIndex = { count: 0, cardinality: 1 }; @@ -91,11 +94,13 @@ const getESQLOverallStatsInChunk = async ({ let countQuery = fieldsToFetch.length > 0 ? '| STATS ' : ''; countQuery += fieldsToFetch.map((field) => field.query).join(','); const query = appendToESQLQuery(esqlBaseQueryWithLimit, countQuery); + const namedParams = getEarliestLatestParams(esqlBaseQueryWithLimit, timeRange); const request = { params: { query, ...(filter ? { filter } : {}), + ...(namedParams.length ? { params: namedParams } : {}), }, }; @@ -194,6 +199,7 @@ export const getESQLOverallStats = async ({ limitSize, totalCount, onError, + timeRange, }: { runRequest: UseCancellableSearch['runRequest']; fields: Column[]; @@ -202,6 +208,7 @@ export const getESQLOverallStats = async ({ limitSize: number; totalCount: number; onError?: HandleErrorCallback; + timeRange?: TimeRange; }) => { const limiter = pLimit(MAX_CONCURRENT_REQUESTS); @@ -218,6 +225,7 @@ export const getESQLOverallStats = async ({ filter, totalCount, onError, + timeRange, }) ) ) diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_date_field_stats.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_date_field_stats.ts index a7ba5a623e5bf..52ac27770a78b 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_date_field_stats.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_date_field_stats.ts @@ -7,8 +7,9 @@ import type { UseCancellableSearch } from '@kbn/ml-cancellable-search'; import type { QueryDslQueryContainer } from '@kbn/data-views-plugin/common/types'; +import type { TimeRange } from '@kbn/es-query'; import { ESQL_ASYNC_SEARCH_STRATEGY } from '@kbn/data-plugin/common'; -import { appendToESQLQuery } from '@kbn/esql-utils'; +import { appendToESQLQuery, getEarliestLatestParams } from '@kbn/esql-utils'; import type { Column } from '../../hooks/esql/use_esql_overall_stats_data'; import { getSafeESQLName } from '../requests/esql_utils'; import type { DateFieldStats, FieldStatsError } from '../../../../../common/types/field_stats'; @@ -18,6 +19,7 @@ interface Params { columns: Column[]; esqlBaseQuery: string; filter?: QueryDslQueryContainer; + timeRange?: TimeRange; } export const getESQLDateFieldStats = async ({ @@ -25,6 +27,7 @@ export const getESQLDateFieldStats = async ({ columns, esqlBaseQuery, filter, + timeRange, }: Params) => { const dateFields = columns.map((field) => { return { @@ -36,12 +39,14 @@ export const getESQLDateFieldStats = async ({ }); if (dateFields.length > 0) { + const namedParams = getEarliestLatestParams(esqlBaseQuery, timeRange); const dateStatsQuery = ' | STATS ' + dateFields.map(({ query }) => query).join(','); const query = appendToESQLQuery(esqlBaseQuery, dateStatsQuery); const request = { params: { query, ...(filter ? { filter } : {}), + ...(namedParams.length ? { params: namedParams } : {}), }, }; try { diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_keyword_fields.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_keyword_fields.ts index 46756a5ef7b4e..a7779dad1aa55 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_keyword_fields.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_keyword_fields.ts @@ -4,12 +4,12 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - +import type { TimeRange } from '@kbn/es-query'; import type { UseCancellableSearch } from '@kbn/ml-cancellable-search'; import type { QueryDslQueryContainer } from '@kbn/data-views-plugin/common/types'; import { ESQL_ASYNC_SEARCH_STRATEGY } from '@kbn/data-plugin/common'; import pLimit from 'p-limit'; -import { appendToESQLQuery } from '@kbn/esql-utils'; +import { appendToESQLQuery, getEarliestLatestParams } from '@kbn/esql-utils'; import type { Column } from '../../hooks/esql/use_esql_overall_stats_data'; import { getSafeESQLName } from '../requests/esql_utils'; import { isFulfilled, isRejected } from '../../../common/util/promise_all_settled_utils'; @@ -22,15 +22,17 @@ interface Params { columns: Column[]; esqlBaseQuery: string; filter?: QueryDslQueryContainer; + timeRange?: TimeRange; } export const getESQLKeywordFieldStats = async ({ runRequest, columns, esqlBaseQuery, filter, + timeRange, }: Params) => { const limiter = pLimit(MAX_CONCURRENT_REQUESTS); - + const namedParams = getEarliestLatestParams(esqlBaseQuery, timeRange); const keywordFields = columns.map((field) => { const query = appendToESQLQuery( esqlBaseQuery, @@ -47,6 +49,7 @@ export const getESQLKeywordFieldStats = async ({ params: { query, ...(filter ? { filter } : {}), + ...(namedParams.length ? { params: namedParams } : {}), }, }, }; diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_numeric_field_stats.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_numeric_field_stats.ts index 2a83954503730..438e756a2d0ad 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_numeric_field_stats.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/esql_requests/get_numeric_field_stats.ts @@ -4,11 +4,11 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - +import type { TimeRange } from '@kbn/es-query'; import type { UseCancellableSearch } from '@kbn/ml-cancellable-search'; import type { QueryDslQueryContainer } from '@kbn/data-views-plugin/common/types'; import { ESQL_ASYNC_SEARCH_STRATEGY } from '@kbn/data-plugin/common'; -import { appendToESQLQuery } from '@kbn/esql-utils'; +import { appendToESQLQuery, getEarliestLatestParams } from '@kbn/esql-utils'; import { chunk } from 'lodash'; import pLimit from 'p-limit'; import type { Column } from '../../hooks/esql/use_esql_overall_stats_data'; @@ -28,12 +28,14 @@ interface Params { columns: Column[]; esqlBaseQuery: string; filter?: QueryDslQueryContainer; + timeRange?: TimeRange; } const getESQLNumericFieldStatsInChunk = async ({ runRequest, columns, esqlBaseQuery, filter, + timeRange, }: Params): Promise> => { // Hashmap of agg to index/order of which is made in the ES|QL query // {min: 0, max: 1, p0: 2, p5: 3, ..., p100: 22} @@ -67,10 +69,12 @@ const getESQLNumericFieldStatsInChunk = async ({ const numericStatsQuery = '| STATS ' + numericFields.map(({ query }) => query).join(','); const query = appendToESQLQuery(esqlBaseQuery, numericStatsQuery); + const namedParams = getEarliestLatestParams(esqlBaseQuery, timeRange); const request = { params: { query, ...(filter ? { filter } : {}), + ...(namedParams.length ? { params: namedParams } : {}), }, }; try { @@ -127,6 +131,7 @@ export const getESQLNumericFieldStats = async ({ columns, esqlBaseQuery, filter, + timeRange, }: Params): Promise> => { const limiter = pLimit(MAX_CONCURRENT_REQUESTS); @@ -142,6 +147,7 @@ export const getESQLNumericFieldStats = async ({ filter, runRequest, esqlBaseQuery, + timeRange, }) ) ) diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/get_data_view_by_index_pattern.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/get_data_view_by_index_pattern.ts index 8ef09d59555ea..fb0e16312f3ce 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/get_data_view_by_index_pattern.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/get_data_view_by_index_pattern.ts @@ -6,7 +6,11 @@ */ import type { DataView, DataViewsContract } from '@kbn/data-views-plugin/public'; -import { getESQLAdHocDataview } from '@kbn/esql-utils'; +import { + getESQLAdHocDataview, + getIndexPatternFromESQLQuery, + getTimeFieldFromESQLQuery, +} from '@kbn/esql-utils'; /** * Get a saved data view that matches the index pattern (as close as possible) @@ -18,24 +22,20 @@ import { getESQLAdHocDataview } from '@kbn/esql-utils'; */ export async function getOrCreateDataViewByIndexPattern( dataViews: DataViewsContract, - indexPatternFromQuery: string | undefined, + query: string, currentDataView: DataView | undefined ) { - if (indexPatternFromQuery) { - const matched = await dataViews.find(indexPatternFromQuery); - - // Only returns persisted data view if it matches index pattern exactly - // Because * in pattern can result in misleading matches (i.e. "kibana*" will return data view with pattern "kibana_1") - // which is not neccessarily the one we want to use - if (matched.length > 0 && matched[0].getIndexPattern() === indexPatternFromQuery) - return matched[0]; - } + const indexPatternFromQuery = getIndexPatternFromESQLQuery(query); + const newTimeField = getTimeFieldFromESQLQuery(query); if ( - indexPatternFromQuery && - (currentDataView?.isPersisted() || indexPatternFromQuery !== currentDataView?.getIndexPattern()) + currentDataView?.isPersisted() || + indexPatternFromQuery !== currentDataView?.getIndexPattern() || + // here the pattern hasn't changed but the time field has + (newTimeField !== currentDataView?.timeFieldName && + indexPatternFromQuery === currentDataView?.getIndexPattern()) ) { - return await getESQLAdHocDataview(indexPatternFromQuery, dataViews); + return await getESQLAdHocDataview(query, dataViews); } return currentDataView; } diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/ui_actions/create_field_stats_table.tsx b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/ui_actions/create_field_stats_table.tsx index 441fbd4d6c5e9..bba19143204aa 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/ui_actions/create_field_stats_table.tsx +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/ui_actions/create_field_stats_table.tsx @@ -12,7 +12,6 @@ import type { EmbeddableApiContext } from '@kbn/presentation-publishing'; import type { UiActionsActionDefinition } from '@kbn/ui-actions-plugin/public'; import { IncompatibleActionError } from '@kbn/ui-actions-plugin/public'; import type { CoreStart } from '@kbn/core-lifecycle-browser'; -import { getIndexPatternFromESQLQuery } from '@kbn/esql-utils'; import { toMountPoint } from '@kbn/react-kibana-mount'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import React from 'react'; @@ -80,10 +79,9 @@ async function updatePanelFromFlyoutEdits({ const update = async (nextUpdate: FieldStatsInitialState) => { const esqlQuery = nextUpdate?.query?.esql; if (isDefined(esqlQuery)) { - const indexPatternFromQuery = getIndexPatternFromESQLQuery(esqlQuery); const dv = await getOrCreateDataViewByIndexPattern( pluginStart.data.dataViews, - indexPatternFromQuery, + esqlQuery, undefined ); if (dv?.id && nextUpdate.dataViewId !== dv.id) { diff --git a/x-pack/plugins/elastic_assistant/server/__mocks__/request_context.ts b/x-pack/plugins/elastic_assistant/server/__mocks__/request_context.ts index c6a9951e89e3e..be3965fd1c26b 100644 --- a/x-pack/plugins/elastic_assistant/server/__mocks__/request_context.ts +++ b/x-pack/plugins/elastic_assistant/server/__mocks__/request_context.ts @@ -123,10 +123,10 @@ const createElasticAssistantRequestContextMock = ( () => clients.elasticAssistant.getAIAssistantKnowledgeBaseDataClient ) as unknown as jest.MockInstance< Promise, - [boolean], + [], unknown > & - ((initializeKnowledgeBase: boolean) => Promise), + (() => Promise), getCurrentUser: jest.fn(), getServerBasePath: jest.fn(), getSpaceId: jest.fn(), diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/get_conversation.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/get_conversation.ts index c4e40caa6654b..94b8531632178 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/get_conversation.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/get_conversation.ts @@ -34,9 +34,9 @@ export const getConversation = async ({ bool: { must: [ { - match: user.profile_uid - ? { 'users.id': user.profile_uid } - : { 'users.name': user.username }, + match: user.username + ? { 'users.name': user.username } + : { 'users.id': user.profile_uid }, }, ], }, diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_service/index.test.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_service/index.test.ts index b9079c59a0643..a11ad418c7bad 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_service/index.test.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_service/index.test.ts @@ -98,6 +98,7 @@ const mockUser1 = { describe('AI Assistant Service', () => { let pluginStop$: Subject; let assistantServiceOpts: AIAssistantServiceOpts; + let ml: MlPluginSetup; beforeEach(() => { jest.resetAllMocks(); @@ -110,12 +111,16 @@ describe('AI Assistant Service', () => { ); clusterClient.indices.getAlias.mockImplementation(async () => GetAliasResponse); clusterClient.indices.getDataStream.mockImplementation(async () => GetDataStreamResponse); + ml = mlPluginMock.createSetupContract() as unknown as MlPluginSetup; // Missing SharedServices mock, so manually mocking trainedModelsProvider + ml.trainedModelsProvider = jest.fn().mockImplementation(() => ({ + getELSER: jest.fn().mockImplementation(() => '.elser_model_2'), + })); assistantServiceOpts = { logger, elasticsearchClientPromise: Promise.resolve(clusterClient), pluginStop$, kibanaVersion: '8.8.0', - ml: mlPluginMock.createSetupContract() as unknown as MlPluginSetup, // Missing SharedServices mock + ml, taskManager: taskManagerMock.createSetup(), }; }); @@ -136,10 +141,11 @@ describe('AI Assistant Service', () => { expect(assistantService.isInitialized()).toEqual(true); - expect(clusterClient.cluster.putComponentTemplate).toHaveBeenCalledTimes(4); + expect(clusterClient.cluster.putComponentTemplate).toHaveBeenCalledTimes(5); const expectedTemplates = [ '.kibana-elastic-ai-assistant-component-template-conversations', + '.kibana-elastic-ai-assistant-component-template-knowledge-base', '.kibana-elastic-ai-assistant-component-template-prompts', '.kibana-elastic-ai-assistant-component-template-anonymization-fields', '.kibana-elastic-ai-assistant-component-template-attack-discovery', @@ -634,12 +640,13 @@ describe('AI Assistant Service', () => { 'AI Assistant service initialized', async () => assistantService.isInitialized() === true ); - expect(clusterClient.cluster.putComponentTemplate).toHaveBeenCalledTimes(6); + expect(clusterClient.cluster.putComponentTemplate).toHaveBeenCalledTimes(7); const expectedTemplates = [ '.kibana-elastic-ai-assistant-component-template-conversations', '.kibana-elastic-ai-assistant-component-template-conversations', '.kibana-elastic-ai-assistant-component-template-conversations', + '.kibana-elastic-ai-assistant-component-template-knowledge-base', '.kibana-elastic-ai-assistant-component-template-prompts', '.kibana-elastic-ai-assistant-component-template-anonymization-fields', '.kibana-elastic-ai-assistant-component-template-attack-discovery', @@ -667,11 +674,12 @@ describe('AI Assistant Service', () => { async () => (await getSpaceResourcesInitialized(assistantService)) === true ); - expect(clusterClient.indices.putIndexTemplate).toHaveBeenCalledTimes(6); + expect(clusterClient.indices.putIndexTemplate).toHaveBeenCalledTimes(7); const expectedTemplates = [ '.kibana-elastic-ai-assistant-index-template-conversations', '.kibana-elastic-ai-assistant-index-template-conversations', '.kibana-elastic-ai-assistant-index-template-conversations', + '.kibana-elastic-ai-assistant-index-template-knowledge-base', '.kibana-elastic-ai-assistant-index-template-prompts', '.kibana-elastic-ai-assistant-index-template-anonymization-fields', '.kibana-elastic-ai-assistant-index-template-attack-discovery', @@ -698,7 +706,7 @@ describe('AI Assistant Service', () => { async () => (await getSpaceResourcesInitialized(assistantService)) === true ); - expect(clusterClient.indices.putSettings).toHaveBeenCalledTimes(6); + expect(clusterClient.indices.putSettings).toHaveBeenCalledTimes(7); }); test('should retry updating index mappings for existing indices for transient ES errors', async () => { @@ -718,7 +726,7 @@ describe('AI Assistant Service', () => { async () => (await getSpaceResourcesInitialized(assistantService)) === true ); - expect(clusterClient.indices.putMapping).toHaveBeenCalledTimes(6); + expect(clusterClient.indices.putMapping).toHaveBeenCalledTimes(7); }); test('should retry creating concrete index for transient ES errors', async () => { @@ -751,7 +759,7 @@ describe('AI Assistant Service', () => { async () => (await getSpaceResourcesInitialized(assistantService)) === true ); - expect(clusterClient.indices.createDataStream).toHaveBeenCalledTimes(5); + expect(clusterClient.indices.createDataStream).toHaveBeenCalledTimes(6); }); }); }); diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_service/index.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_service/index.ts index 02d54ef31ab75..56dabd5978b9f 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_service/index.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_service/index.ts @@ -66,8 +66,6 @@ export type CreateDataStream = (params: { export class AIAssistantService { private initialized: boolean; - // Temporary 'feature flag' to determine if we should initialize the knowledge base, toggled when accessing data client - private initializeKnowledgeBase: boolean = false; private isInitializing: boolean = false; private getElserId: GetElser; private conversationsDataStream: DataStreamSpacesAdapter; @@ -124,6 +122,7 @@ export class AIAssistantService { public getIsKBSetupInProgress() { return this.isKBSetupInProgress; } + public setIsKBSetupInProgress(isInProgress: boolean) { this.isKBSetupInProgress = isInProgress; } @@ -172,34 +171,32 @@ export class AIAssistantService { pluginStop$: this.options.pluginStop$, }); - if (this.initializeKnowledgeBase) { - await this.knowledgeBaseDataStream.install({ - esClient, - logger: this.options.logger, - pluginStop$: this.options.pluginStop$, - }); + await this.knowledgeBaseDataStream.install({ + esClient, + logger: this.options.logger, + pluginStop$: this.options.pluginStop$, + }); - // TODO: Pipeline creation is temporary as we'll be moving to semantic_text field once available in ES - const pipelineCreated = await pipelineExists({ + // TODO: Pipeline creation is temporary as we'll be moving to semantic_text field once available in ES + const pipelineCreated = await pipelineExists({ + esClient, + id: this.resourceNames.pipelines.knowledgeBase, + }); + if (!pipelineCreated) { + this.options.logger.debug( + `Installing ingest pipeline - ${this.resourceNames.pipelines.knowledgeBase}` + ); + const response = await createPipeline({ esClient, id: this.resourceNames.pipelines.knowledgeBase, + modelId: await this.getElserId(), }); - if (!pipelineCreated) { - this.options.logger.debug( - `Installing ingest pipeline - ${this.resourceNames.pipelines.knowledgeBase}` - ); - const response = await createPipeline({ - esClient, - id: this.resourceNames.pipelines.knowledgeBase, - modelId: await this.getElserId(), - }); - this.options.logger.debug(`Installed ingest pipeline: ${response}`); - } else { - this.options.logger.debug( - `Ingest pipeline already exists - ${this.resourceNames.pipelines.knowledgeBase}` - ); - } + this.options.logger.debug(`Installed ingest pipeline: ${response}`); + } else { + this.options.logger.debug( + `Ingest pipeline already exists - ${this.resourceNames.pipelines.knowledgeBase}` + ); } await this.promptsDataStream.install({ @@ -330,15 +327,8 @@ export class AIAssistantService { } public async createAIAssistantKnowledgeBaseDataClient( - opts: CreateAIAssistantClientParams & { initializeKnowledgeBase: boolean } + opts: CreateAIAssistantClientParams ): Promise { - // Note: Due to plugin lifecycle and feature flag registration timing, we need to pass in the feature flag here - // Remove this param and initialization when the `assistantKnowledgeBaseByDefault` feature flag is removed - if (opts.initializeKnowledgeBase) { - this.initializeKnowledgeBase = true; - await this.initializeResources(); - } - const res = await this.checkResourcesInstallation(opts); if (res === null) { @@ -446,13 +436,11 @@ export class AIAssistantService { await this.conversationsDataStream.installSpace(spaceId); } - if (this.initializeKnowledgeBase) { - const knowledgeBaseIndexName = await this.knowledgeBaseDataStream.getInstalledSpaceName( - spaceId - ); - if (!knowledgeBaseIndexName) { - await this.knowledgeBaseDataStream.installSpace(spaceId); - } + const knowledgeBaseIndexName = await this.knowledgeBaseDataStream.getInstalledSpaceName( + spaceId + ); + if (!knowledgeBaseIndexName) { + await this.knowledgeBaseDataStream.installSpace(spaceId); } const promptsIndexName = await this.promptsDataStream.getInstalledSpaceName(spaceId); diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0001.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0001.asciidoc index a9373d4eec246..4db517c93ce22 100644 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0001.asciidoc +++ b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0001.asciidoc @@ -1,16 +1,7 @@ -[[esql-example-queries]] - -The following is an example ES|QL query: - -``` -FROM logs-* -| WHERE NOT CIDR_MATCH(destination.ip, "10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16") -| STATS destcount = COUNT(destination.ip) by user.name, host.name -| ENRICH ldap_lookup_new ON user.name -| WHERE group.name IS NOT NULL -| EVAL follow_up = CASE( - destcount >= 100, "true", - "false") -| SORT destcount desc -| KEEP destcount, host.name, user.name, group.name, follow_up -``` +// 1. regex to extract from dns.question.registered_domain +// Helpful when asking how to use GROK to extract values via REGEX +from logs-* +| where dns.question.name like "?*" +| grok dns.question.name """(?[a-zA-Z0-9]+\.[a-z-A-Z]{2,3}$)""" +| keep dns_registered_domain +| limit 10 diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0002.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0002.asciidoc index cb4e25ba9e0c3..1c9df943031f5 100644 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0002.asciidoc +++ b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0002.asciidoc @@ -1,11 +1,10 @@ -[[esql-example-queries]] - -The following is an example ES|QL query: - -``` +// 2. hunting scheduled task with suspicious actions via registry.data.bytes +// Helpful when answering questions on regex based searches and replacements (RLIKE and REPLACE), base64 conversions, and dealing with case sensitivity from logs-* -| grok dns.question.name "%{DATA}\\.%{GREEDYDATA:dns.question.registered_domain:string}" -| stats unique_queries = count_distinct(dns.question.name) by dns.question.registered_domain, process.name -| where unique_queries > 5 -| sort unique_queries desc -``` +| where host.os.type == "windows" and event.category == "registry" and event.action == "modification" and +registry.path like """HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Schedule\\TaskCache\\Tasks\\*Actions*""" +| eval scheduled_task_action = replace(TO_LOWER(FROM_BASE64(registry.data.bytes)), """\u0000""", "") +| eval scheduled_task_action = replace(scheduled_task_action, """(\u0003\fauthorfff|\u0003\fauthorff\u000e)""", "") +| where scheduled_task_action rlike """.*(users\\public\\|\\appdata\\roaming|programdata|powershell|rundll32|regsvr32|mshta.exe|cscript.exe|wscript.exe|cmd.exe|forfiles|msiexec).*""" and not scheduled_task_action like "localsystem*" +| keep scheduled_task_action, registry.path, agent.id +| stats count_agents = count_distinct(agent.id) by scheduled_task_action | where count_agents == 1 \ No newline at end of file diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0003.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0003.asciidoc index 61d4c48a810c5..70897339c1b48 100644 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0003.asciidoc +++ b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0003.asciidoc @@ -1,14 +1,10 @@ -[[esql-example-queries]] - -The following is an example ES|QL query: - -``` +// 3. suspicious powershell cmds from base64 encoded cmdline +// Helpful when answering questions on regex based searches and replacements, base64 conversions, and dealing with case sensitivity (TO_LOWER and TO_UPPER commands) from logs-* -| where event.code is not null -| stats event_code_count = count(event.code) by event.code,host.name -| enrich win_events on event.code with EVENT_DESCRIPTION -| where EVENT_DESCRIPTION is not null and host.name is not null -| rename EVENT_DESCRIPTION as event.description -| sort event_code_count desc -| keep event_code_count,event.code,host.name,event.description -``` +| where host.os.type == "windows" and event.category == "process" and event.action == "start" and TO_LOWER(process.name) == "powershell.exe" and process.command_line rlike ".+ -(e|E).*" +| keep agent.id, process.command_line +| grok process.command_line """(?([A-Za-z0-9+/]+={1,2}$|[A-Za-z0-9+/]{100,}))""" +| where base64_data is not null +| eval decoded_base64_cmdline = replace(TO_LOWER(FROM_BASE64(base64_data)), """\u0000""", "") +| where decoded_base64_cmdline rlike """.*(http|webclient|download|mppreference|sockets|bxor|.replace|reflection|assembly|load|bits|start-proc|iwr|frombase64).*""" +| keep agent.id, process.command_line, decoded_base64_cmdline \ No newline at end of file diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0004.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0004.asciidoc index 3a66208bfa158..eb4f1f4088f0f 100644 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0004.asciidoc +++ b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0004.asciidoc @@ -1,15 +1,8 @@ -[[esql-example-queries]] - -The following is an example ES|QL query: - -``` +//4. Detect masquerading attempts as native Windows binaries +//MITRE Tactics: "Defense Evasion" from logs-* -| where event.category == "file" and event.action == "creation" -| stats filecount = count(file.name) by process.name,host.name -| dissect process.name "%{process}.%{extension}" -| eval proclength = length(process.name) -| where proclength > 10 -| sort filecount,proclength desc -| limit 10 -| keep host.name,process.name,filecount,process,extension,fullproc,proclength -``` +| where event.type == "start" and event.action == "start" and host.os.name == "Windows" and not starts_with(process.executable, "C:\\Program Files\\WindowsApps\\") and not starts_with(process.executable, "C:\\Windows\\System32\\DriverStore\\") and process.name != "setup.exe" +| keep process.name.caseless, process.executable.caseless, process.code_signature.subject_name, process.code_signature.trusted, process.code_signature.exists, host.id +| eval system_bin = case(starts_with(process.executable.caseless, "c:\\windows\\system32") and starts_with(process.code_signature.subject_name, "Microsoft") and process.code_signature.trusted == true, process.name.caseless, null), non_system_bin = case(process.code_signature.exists == false or process.code_signature.trusted != true or not starts_with(process.code_signature.subject_name, "Microsoft"), process.name.caseless, null) +| stats count_system_bin = count(system_bin), count_non_system_bin = count(non_system_bin) by process.name.caseless, host.id +| where count_system_bin >= 1 and count_non_system_bin >= 1 \ No newline at end of file diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0005.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0005.asciidoc index d5a42c7ce21fd..8ca58266275c7 100644 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0005.asciidoc +++ b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0005.asciidoc @@ -1,13 +1,12 @@ -[[esql-example-queries]] - -The following is an example ES|QL query: - -``` +//5. Detect DLL Hijack via Masquerading as Microsoft Native Libraries +// Helpful when asking how to use ENRICH query results with enrich policies from logs-* -| where process.name == "curl.exe" -| stats bytes = sum(destination.bytes) by destination.address -| eval kb = bytes/1024 -| sort kb desc -| limit 10 -| keep kb,destination.address -``` +| where host.os.family == "windows" and event.action == "load" and process.code_signature.status == "trusted" and dll.code_signature.status != "trusted" and +not dll.path rlike """[c-fC-F]:\\(Windows|windows|WINDOWS)\\(System32|SysWOW64|system32|syswow64)\\[a-zA-Z0-9_]+.dll""" +| keep dll.name, dll.path, dll.hash.sha256, process.executable, host.id +| ENRICH libs-policy-defend +| where native == "yes" and not starts_with(dll.path, "C:\\Windows\\assembly\\NativeImages") +| eval process_path = replace(process.executable, """([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}|ns[a-z][A-Z0-9]{3,4}\.tmp|DX[A-Z0-9]{3,4}\.tmp|7z[A-Z0-9]{3,5}\.tmp|[0-9\.\-\_]{3,})""", ""), +dll_path = replace(dll.path, """([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}|ns[a-z][A-Z0-9]{3,4}\.tmp|DX[A-Z0-9]{3,4}\.tmp|7z[A-Z0-9]{3,5}\.tmp|[0-9\.\-\_]{3,})""", "") +| stats host_count = count_distinct(host.id) by dll.name, dll_path, process_path, dll.hash.sha256 +| sort host_count asc \ No newline at end of file diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0006.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0006.asciidoc index 26009eccaf4a9..47d7c496ff4e1 100644 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0006.asciidoc +++ b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0006.asciidoc @@ -1,10 +1,11 @@ -[[esql-example-queries]] - -The following is an example ES|QL query: - -``` -FROM metrics-apm* -| WHERE metricset.name == "transaction" AND metricset.interval == "1m" -| EVAL bucket = AUTO_BUCKET(transaction.duration.histogram, 50, , ) -| STATS avg_duration = AVG(transaction.duration.histogram) BY bucket -``` +//6. Potential Exfiltration by process total egress bytes +// Helpful when asking how to filter/search on IP address (CIDR_MATCH) fields and aggregating/grouping +//MITRE Tactics: "Command and Control", "Exfiltration" +from logs-* +| where host.os.family == "windows" and event.category == "network" and +event.action == "disconnect_received" and +not CIDR_MATCH(destination.ip, "10.0.0.0/8", "127.0.0.0/8", "169.254.0.0/16", "172.16.0.0/12", "192.0.0.0/24", "192.0.0.0/29", "192.0.0.8/32", "192.0.0.9/32", "192.0.0.10/32", "192.0.0.170/32", "192.0.0.171/32", "192.0.2.0/24", "192.31.196.0/24", "192.52.193.0/24", "192.168.0.0/16", "192.88.99.0/24", "224.0.0.0/4", "100.64.0.0/10", "192.175.48.0/24","198.18.0.0/15", "198.51.100.0/24", "203.0.113.0/24", "240.0.0.0/4", "::1","FE80::/10", "FF00::/8") +| keep source.bytes, destination.address, process.executable, process.entity_id +| stats total_bytes_out = sum(source.bytes) by process.entity_id, destination.address, process.executable +/* more than 1GB out by same process.pid in 8 hours */ +| where total_bytes_out >= 1073741824 \ No newline at end of file diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0007.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0007.asciidoc index 88e0b2260ff11..64e6cb75c1ad0 100644 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0007.asciidoc +++ b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0007.asciidoc @@ -1,10 +1,13 @@ -[[esql-example-queries]] - -The following is an example ES|QL query: - -``` -FROM packetbeat-* -| STATS doc_count = COUNT(destination.domain) BY destination.domain -| SORT doc_count DESC -| LIMIT 10 -``` +//7. Windows logon activity by source IP +// Helpful when answering questions about the CASE command (as well as conditional outputs/if statements) +//MITRE Tactics: "Credential Access" +from logs-* +| where host.os.family == "windows" and +event.category == "authentication" and event.action in ("logon-failed", "logged-in") and winlog.logon.type == "Network" and +source.ip is not null and +/* noisy failure status codes often associated to authentication misconfiguration */ +not (event.action == "logon-failed" and winlog.event_data.Status in ("0xC000015B", "0XC000005E", "0XC0000133", "0XC0000192")) +| eval failed = case(event.action == "logon-failed", source.ip, null), success = case(event.action == "logged-in", source.ip, null) +| stats count_failed = count(failed), count_success = count(success), count_user = count_distinct(winlog.event_data.TargetUserName) by source.ip +/* below threshold should be adjusted to your env logon patterns */ +| where count_failed >= 100 and count_success <= 10 and count_user >= 20 \ No newline at end of file diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0008.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0008.asciidoc index 333ae968c020c..3a7002cc7d7d6 100644 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0008.asciidoc +++ b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0008.asciidoc @@ -1,11 +1,17 @@ -[[esql-example-queries]] - -The following is an example ES|QL query: - -``` -FROM employees -| EVAL hire_date_formatted = DATE_FORMAT(hire_date, "MMMM yyyy") -| SORT hire_date -| KEEP emp_no, hire_date_formatted -| LIMIT 5 -``` +//8. High count of network connection over extended period by process +//Helpful when answering questions about IP searches/filters, field converstions(to_double, to_int), and running multiple aggregations +//MITRE Tactics: "Command and Control" +from logs-* +| where host.os.family == "windows" and event.category == "network" and +network.direction == "egress" and (process.executable like "C:\\\\Windows\\\\System32*" or process.executable like "C:\\\\Windows\\\\SysWOW64\\\\*") and not user.id in ("S-1-5-19", "S-1-5-20") and +/* multiple Windows svchost services perform long term connection to MS ASN, can be covered in a dedicated hunt */ +not (process.name == "svchost.exe" and user.id == "S-1-5-18") and +/* excluding private IP ranges */ +not CIDR_MATCH(destination.ip, "10.0.0.0/8", "127.0.0.0/8", "169.254.0.0/16", "172.16.0.0/12", "192.0.0.0/24", "192.0.0.0/29", "192.0.0.8/32", "192.0.0.9/32", "192.0.0.10/32", "192.0.0.170/32", "192.0.0.171/32", "192.0.2.0/24", "192.31.196.0/24", "192.52.193.0/24", "192.168.0.0/16", "192.88.99.0/24", "224.0.0.0/4", "100.64.0.0/10", "192.175.48.0/24","198.18.0.0/15", "198.51.100.0/24", "203.0.113.0/24", "240.0.0.0/4", "::1","FE80::/10", "FF00::/8") +| keep source.bytes, destination.address, process.name, process.entity_id, @timestamp +/* calc total duration , total MB out and the number of connections per hour */ +| stats total_bytes_out = sum(source.bytes), count_connections = count(*), start_time = min(@timestamp), end_time = max(@timestamp) by process.entity_id, destination.address, process.name +| eval dur = TO_DOUBLE(end_time)-TO_DOUBLE(start_time), duration_hours=TO_INT(dur/3600000), MB_out=TO_DOUBLE(total_bytes_out) / (1024*1024), number_of_con_per_hour = (count_connections / duration_hours) +| keep process.entity_id, process.name, duration_hours, destination.address, MB_out, count_connections, number_of_con_per_hour +/* threshold is set to 120 connections per minute , you can adjust it to your env/FP rate */ +| where duration_hours >= 1 and number_of_con_per_hour >= 120 \ No newline at end of file diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0009.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0009.asciidoc index f9762b0f695be..0f1f8f0918246 100644 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0009.asciidoc +++ b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0009.asciidoc @@ -1,7 +1,12 @@ -[[esql-example-queries]] - -The following is NOT an example of an ES|QL query: - -``` -Pagination is not supported -``` +//9. Persistence via Suspicious Launch Agent or Launch Daemon with low occurrence +//Helpful when answering questions on concatenating fields, dealing with time based searches +//MITRE Tactics: "Persistence" +from logs-* +| where @timestamp > now() - 7 day +| where host.os.family == "macos" and event.category == "file" and event.action == "launch_daemon" and +(Persistence.runatload == true or Persistence.keepalive == true) and process.executable is not null +| eval args = MV_CONCAT(Persistence.args, ",") +/* normalizing users home profile */ +| eval args = replace(args, """/Users/[a-zA-Z0-9ñ\.\-\_\$~ ]+/""", "/Users/user/") +| stats agents = count_distinct(host.id), total = count(*) by process.name, Persistence.name, args +| where starts_with(args, "/") and agents == 1 and total == 1 \ No newline at end of file diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0010.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0010.asciidoc index ee361169eecf0..4c3c558fec065 100644 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0010.asciidoc +++ b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0010.asciidoc @@ -1,11 +1,15 @@ -[[esql-example-queries]] - -The following is an example ES|QL query: - -``` -FROM logs-* -| WHERE @timestamp >= NOW() - 15 minutes -| EVAL bucket = DATE_TRUNC(1 minute, @timestamp) -| STATS avg_cpu = AVG(system.cpu.total.norm.pct) BY bucket, host.name -| LIMIT 10 -``` +//10. Suspicious Network Connections by unsigned macO +//Helpful when answering questions on IP filtering, calculating the time difference between timestamps, aggregations, and field conversions +//MITRE Tactics: "Command and Control" +from logs-* +| where host.os.family == "macos" and event.category == "network" and +(process.code_signature.exists == false or process.code_signature.trusted != true) and +/* excluding private IP ranges */ +not CIDR_MATCH(destination.ip, "10.0.0.0/8", "127.0.0.0/8", "169.254.0.0/16", "172.16.0.0/12", "192.0.0.0/24", "192.0.0.0/29", "192.0.0.8/32", "192.0.0.9/32", "192.0.0.10/32", "192.0.0.170/32", "192.0.0.171/32", "192.0.2.0/24", "192.31.196.0/24", "192.52.193.0/24", "192.168.0.0/16", "192.88.99.0/24", "224.0.0.0/4", "100.64.0.0/10", "192.175.48.0/24","198.18.0.0/15", "198.51.100.0/24", "203.0.113.0/24", "240.0.0.0/4", "::1","FE80::/10", "FF00::/8") +| keep source.bytes, destination.address, process.name, process.entity_id, @timestamp +/* calc total duration , total MB out and the number of connections per hour */ +| stats total_bytes_out = sum(source.bytes), count_connections = count(*), start_time = min(@timestamp), end_time = max(@timestamp) by process.entity_id, destination.address, process.name +| eval dur = TO_DOUBLE(end_time)-TO_DOUBLE(start_time), duration_hours=TO_INT(dur/3600000), MB_out=TO_DOUBLE(total_bytes_out) / (1024*1024), number_of_con_per_hour = (count_connections / duration_hours) +| keep process.entity_id, process.name, duration_hours, destination.address, MB_out, count_connections, number_of_con_per_hour +/* threshold is set to 120 connections per minute , you can adjust it to your env/FP rate */ +| where duration_hours >= 8 and number_of_con_per_hour >= 120 \ No newline at end of file diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0011.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0011.asciidoc index 0e3cf73139ff9..3ea806a7d90dc 100644 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0011.asciidoc +++ b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0011.asciidoc @@ -1,13 +1,15 @@ -[[esql-example-queries]] - -The following is an example ES|QL query: - -``` -FROM traces-apm* -| WHERE @timestamp >= NOW() - 24 hours -| EVAL successful = CASE(event.outcome == "success", 1, 0), - failed = CASE(event.outcome == "failure", 1, 0) -| STATS success_rate = AVG(successful), - avg_duration = AVG(transaction.duration), - total_requests = COUNT(transaction.id) BY service.name -``` +//11. Unusual file creations by web server user +//Helpful when answering questions on using the LIKE command (wildcard searches) and aggregations +FROM logs-* +| WHERE @timestamp > NOW() - 50 day +| WHERE host.os.type == "linux" and event.type == "creation" and user.name in ("www-data", "apache", "nginx", "httpd", "tomcat", "lighttpd", "glassfish", "weblogic") and ( +file.path like "/var/www/*" or +file.path like "/var/tmp/*" or +file.path like "/tmp/*" or +file.path like "/dev/shm/*" +) +| STATS file_count = COUNT(file.path), host_count = COUNT(host.name) by file.path, host.name, process.name, user.name +// Alter this threshold to make sense for your environment +| WHERE file_count <= 5 +| SORT file_count asc +| LIMIT 100 \ No newline at end of file diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0012.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0012.asciidoc index e940b57368fbf..7b0f340d4ea3e 100644 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0012.asciidoc +++ b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0012.asciidoc @@ -1,9 +1,6 @@ -[[esql-example-queries]] - -The following is an example ES|QL query: - -``` -FROM metricbeat* -| EVAL cpu_pct_normalized = (system.cpu.user.pct + system.cpu.system.pct) / system.cpu.cores -| STATS AVG(cpu_pct_normalized) BY host.name -``` +//12. Segmentation Fault & Potential Buffer Overflow Hunting +//Helpful when answering questions on extractions with GROK +FROM logs-* +| WHERE host.os.type == "linux" and process.name == "kernel" and message like "*segfault*" +| GROK message "\\[%{NUMBER:timestamp}\\] %{WORD:process}\\[%{NUMBER:pid}\\]: segfault at %{BASE16NUM:segfault_address} ip %{BASE16NUM:instruction_pointer} sp %{BASE16NUM:stack_pointer} error %{NUMBER:error_code} in %{DATA:so_file}\\[%{BASE16NUM:so_base_address}\\+%{BASE16NUM:so_offset}\\]" +| KEEP timestamp, process, pid, so_file, segfault_address, instruction_pointer, stack_pointer, error_code, so_base_address, so_offset \ No newline at end of file diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0013.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0013.asciidoc index 657b5e7397ab5..445645991bee3 100644 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0013.asciidoc +++ b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0013.asciidoc @@ -1,10 +1,64 @@ -[[esql-example-queries]] +//13. Persistence via Systemd (timers) +//Helpful when answering questions on using the CASE command (conditional statements), searching lists using the IN command, wildcard searches with the LIKE command and aggregations +FROM logs-* +| WHERE host.os.type == "linux" and event.type in ("creation", "change") and ( -The following is an example ES|QL query: + // System-wide/user-specific services/timers (root permissions required) + file.path like "/run/systemd/system/*" or + file.path like "/etc/systemd/system/*" or + file.path like "/etc/systemd/user/*" or + file.path like "/usr/local/lib/systemd/system/*" or + file.path like "/lib/systemd/system/*" or + file.path like "/usr/lib/systemd/system/*" or + file.path like "/usr/lib/systemd/user/*" or -``` -FROM postgres-logs -| DISSECT message "%{} duration: %{query_duration} ms" -| EVAL query_duration_num = TO_DOUBLE(query_duration) -| STATS avg_duration = AVG(query_duration_num) -``` + // user-specific services/timers (user permissions required) + file.path like "/home/*/.config/systemd/user/*" or + file.path like "/home/*/.local/share/systemd/user/*" or + + // System-wide generators (root permissions required) + file.path like "/etc/systemd/system-generators/*" or + file.path like "/usr/local/lib/systemd/system-generators/*" or + file.path like "/lib/systemd/system-generators/*" or + file.path like "/etc/systemd/user-generators/*" or + file.path like "/usr/local/lib/systemd/user-generators/*" or + file.path like "/usr/lib/systemd/user-generators/*" + +) and not ( +process.name in ( +"dpkg", "dockerd", "yum", "dnf", "snapd", "pacman", "pamac-daemon", +"netplan", "systemd", "generate" +) or +process.executable == "/proc/self/exe" or +process.executable like "/dev/fd/*" or +file.extension in ("dpkg-remove", "swx", "swp") +) +| EVAL persistence = CASE( + + // System-wide/user-specific services/timers (root permissions required) + file.path like "/run/systemd/system/*" or + file.path like "/etc/systemd/system/*" or + file.path like "/etc/systemd/user/*" or + file.path like "/usr/local/lib/systemd/system/*" or + file.path like "/lib/systemd/system/*" or + file.path like "/usr/lib/systemd/system/*" or + file.path like "/usr/lib/systemd/user/*" or + + // user-specific services/timers (user permissions required) + file.path like "/home/*/.config/systemd/user/*" or + file.path like "/home/*/.local/share/systemd/user/*" or + + // System-wide generators (root permissions required) + file.path like "/etc/systemd/system-generators/*" or + file.path like "/usr/local/lib/systemd/system-generators/*" or + file.path like "/lib/systemd/system-generators/*" or + file.path like "/etc/systemd/user-generators/*" or + file.path like "/usr/local/lib/systemd/user-generators/*" or + file.path like "/usr/lib/systemd/user-generators/*", + process.name, + null +) +| STATS cc = COUNT(*), pers_count = COUNT(persistence), agent_count = COUNT(agent.id) by process.executable, file.path, host.name, user.name +| WHERE pers_count > 0 and pers_count <= 20 and agent_count <= 3 +| SORT cc asc +| LIMIT 100 \ No newline at end of file diff --git a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0014.asciidoc b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0014.asciidoc index d303642641aa3..517d6a4ee2a29 100644 --- a/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0014.asciidoc +++ b/x-pack/plugins/elastic_assistant/server/knowledge_base/esql/example_queries/esql_example_query_0014.asciidoc @@ -1,9 +1,12 @@ -[[esql-example-queries]] - -The following is an example ES|QL query: - -``` -FROM nyc_taxis -| WHERE DATE_EXTRACT(drop_off_time, "hour") >= 6 AND DATE_EXTRACT(drop_off_time, "hour") < 10 -| LIMIT 10 -``` +//14. Low Frequency AWS EC2 Admin Password Retrieval Attempts from Unusual ARNs +//Helpful when answering questions on extracting fields with the dissect command and aggregations. Also an example for hunting for cloud threats +from logs-* +| where event.provider == "ec2.amazonaws.com" and event.action == "GetPasswordData" +and aws.cloudtrail.error_code == "Client.UnauthorizedOperation" and aws.cloudtrail.user_identity.type == "AssumedRole" +| dissect aws.cloudtrail.request_parameters "{%{key}=%{instance_id}}" +| dissect aws.cloudtrail.user_identity.session_context.session_issuer.arn "%{?keyword1}:%{?keyword2}:%{?keyword3}::%{account_id}:%{keyword4}/%{arn_name}" +| dissect user.id "%{principal_id}:%{session_name}" +| keep aws.cloudtrail.user_identity.session_context.session_issuer.principal_id, instance_id, account_id, arn_name, source.ip, principal_id, session_name, user.name +| stats instance_counts = count_distinct(arn_name) by instance_id, user.name, source.ip, session_name +| where instance_counts < 5 +| sort instance_counts desc \ No newline at end of file diff --git a/x-pack/plugins/elastic_assistant/server/lib/data_stream/documents_data_writer.ts b/x-pack/plugins/elastic_assistant/server/lib/data_stream/documents_data_writer.ts index 2b8e7237435ba..87ec80568dbdd 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/data_stream/documents_data_writer.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/data_stream/documents_data_writer.ts @@ -67,10 +67,16 @@ export class DocumentsDataWriter implements DocumentsDataWriter { return { errors: [], docs_created: [], docs_deleted: [], docs_updated: [], took: 0 }; } - const { errors, items, took } = await this.options.esClient.bulk({ - refresh: 'wait_for', - body: await this.buildBulkOperations(params), - }); + const { errors, items, took } = await this.options.esClient.bulk( + { + refresh: 'wait_for', + body: await this.buildBulkOperations(params), + }, + { + // Increasing timout to 2min as KB docs were failing to load after 30s + requestTimeout: 120000, + } + ); return { errors: errors ? this.formatErrorsResponse(items) : [], diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.test.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.test.ts index 6f05edbed007b..925ac5826fea6 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.test.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.test.ts @@ -97,7 +97,6 @@ const esStoreMock = new ElasticsearchStore( ); const defaultProps: AgentExecutorParams = { actionsClient, - isEnabledKnowledgeBase: true, connectorId: mockConnectorId, esClient: esClientMock, esStore: esStoreMock, diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.ts index cd1a032406326..123ca4292324b 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/execute_custom_llm_chain/index.ts @@ -35,7 +35,6 @@ export const callAgentExecutor: AgentExecutor = async ({ abortSignal, actionsClient, alertsIndexPattern, - isEnabledKnowledgeBase, assistantTools = [], connectorId, esClient, @@ -51,6 +50,7 @@ export const callAgentExecutor: AgentExecutor = async ({ size, traceOptions, dataClients, + conversationId, }) => { const isOpenAI = llmType === 'openai'; const llmClass = isOpenAI ? ActionsClientChatOpenAI : ActionsClientSimpleChatModel; @@ -105,7 +105,7 @@ export const callAgentExecutor: AgentExecutor = async ({ anonymizationFields, chain, esClient, - isEnabledKnowledgeBase, + isEnabledKnowledgeBase: true, llm, logger, modelExists, @@ -274,6 +274,7 @@ export const callAgentExecutor: AgentExecutor = async ({ trace_data: traceData, replacements, status: 'ok', + conversationId, }, headers: { 'content-type': 'application/json', 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 7af0b459f4bc9..256bbca81b1c6 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 @@ -37,7 +37,6 @@ export interface AgentExecutorParams { abortSignal?: AbortSignal; alertsIndexPattern?: string; actionsClient: PublicMethodsOf; - isEnabledKnowledgeBase: boolean; assistantTools?: AssistantTool[]; connectorId: string; conversationId?: 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 882726a85ef21..c9d5512238808 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 @@ -77,6 +77,8 @@ export const streamGraph = async ({ streamingSpan?.end(); }; + let finalMessage = ''; + let conversationId: string | undefined; const stream = assistantGraph.streamEvents(inputs, { callbacks: [apmTracer, ...(traceOptions?.tracers ?? [])], runName: DEFAULT_ASSISTANT_GRAPH_ID, @@ -84,7 +86,6 @@ export const streamGraph = async ({ tags: traceOptions?.tags ?? [], version: 'v1', }); - let finalMessage = ''; let currentOutput = ''; let finalOutputIndex = -1; @@ -168,6 +169,9 @@ export const streamGraph = async ({ return handleStreamEnd(finalMessage); } logger.error(`Error streaming from LangChain: ${error.message}`); + if (conversationId) { + push({ payload: `Conversation id: ${conversationId}`, type: 'content' }); + } push({ payload: error.message, type: 'content' }); handleStreamEnd(error.message, true); } @@ -189,6 +193,7 @@ interface InvokeGraphParams { interface InvokeGraphResponse { output: string; traceData: TraceData; + conversationId?: string; } /** @@ -217,18 +222,17 @@ export const invokeGraph = async ({ }; span.addLabels({ evaluationId: traceOptions?.evaluationId }); } - const r = await assistantGraph.invoke(inputs, { callbacks: [apmTracer, ...(traceOptions?.tracers ?? [])], runName: DEFAULT_ASSISTANT_GRAPH_ID, tags: traceOptions?.tags ?? [], }); const output = r.agentOutcome.returnValues.output; - + const conversationId = r.conversation?.id; if (onLlmResponse) { await onLlmResponse(output, traceData); } - return { output, traceData }; + return { output, traceData, conversationId }; }); }; 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 87437a98898d4..ad2e7e50f67f7 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 @@ -29,7 +29,6 @@ export const callAssistantGraph: AgentExecutor = async ({ abortSignal, actionsClient, alertsIndexPattern, - isEnabledKnowledgeBase, assistantTools = [], connectorId, conversationId, @@ -87,6 +86,9 @@ export const callAssistantGraph: AgentExecutor = async ({ // Create a chain that uses the ELSER backed ElasticsearchStore, override k=10 for esql query generation for now const chain = RetrievalQAChain.fromLLM(llm, esStore.asRetriever(10)); + // Check if KB is available + const isEnabledKnowledgeBase = (await dataClients?.kbDataClient?.isModelDeployed()) ?? false; + // Fetch any applicable tools that the source plugin may have registered const assistantToolParams: AssistantToolParams = { alertsIndexPattern, @@ -137,7 +139,15 @@ export const callAssistantGraph: AgentExecutor = async ({ const inputs = { input: latestMessage[0]?.content as string }; if (isStream) { - return streamGraph({ apmTracer, assistantGraph, inputs, logger, onLlmResponse, request }); + return streamGraph({ + apmTracer, + assistantGraph, + inputs, + logger, + onLlmResponse, + request, + traceOptions, + }); } const graphResponse = await invokeGraph({ @@ -155,6 +165,7 @@ export const callAssistantGraph: AgentExecutor = async ({ trace_data: graphResponse.traceData, replacements, status: 'ok', + ...(graphResponse.conversationId ? { conversationId: graphResponse.conversationId } : {}), }, headers: { 'content-type': 'application/json', diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/execute_tools.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/execute_tools.ts index ae33faee3e227..f2eb766b806b8 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/execute_tools.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/execute_tools.ts @@ -40,6 +40,7 @@ export const executeTools = async ({ config, logger, state, tools }: ExecuteTool } const out = await toolExecutor.invoke(agentAction, config); return { + ...state, steps: [{ action: agentAction, observation: JSON.stringify(out, null, 2) }], }; }; diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/generate_chat_title.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/generate_chat_title.ts index 105b625cd5f36..c9fa5c98ef470 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/generate_chat_title.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/generate_chat_title.ts @@ -37,10 +37,6 @@ export const generateChatTitle = async ({ }: GenerateChatTitleParams) => { logger.debug(() => `Node state:\n ${JSON.stringify(state, null, 2)}`); - if (state.messages.length !== 0) { - logger.debug('No need to generate chat title, messages already exist'); - return { chatTitle: '' }; - } const outputParser = new StringOutputParser(); const graph = GENERATE_CHAT_TITLE_PROMPT(responseLanguage).pipe(model).pipe(outputParser); @@ -50,6 +46,7 @@ export const generateChatTitle = async ({ logger.debug(`chatTitle: ${chatTitle}`); return { + ...state, chatTitle, }; }; diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/get_persisted_conversation.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/get_persisted_conversation.ts index 6dbf284e462c4..8f4b285410fbd 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/get_persisted_conversation.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/get_persisted_conversation.ts @@ -27,6 +27,7 @@ export const getPersistedConversation = async ({ if (!conversationId) { logger.debug('Cannot get conversation, because conversationId is undefined'); return { + ...state, conversation: undefined, messages: [], chatTitle: '', @@ -38,6 +39,7 @@ export const getPersistedConversation = async ({ if (!conversation) { logger.debug('Requested conversation, because conversation is undefined'); return { + ...state, conversation: undefined, messages: [], chatTitle: '', @@ -49,6 +51,7 @@ export const getPersistedConversation = async ({ const messages = getLangChainMessages(conversation.messages ?? []); return { + ...state, conversation, messages, chatTitle: conversation.title, diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/persist_conversation_changes.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/persist_conversation_changes.ts index 615c4b2449c4c..40717d7d64e78 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/persist_conversation_changes.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/persist_conversation_changes.ts @@ -57,6 +57,7 @@ export const persistConversationChanges = async ({ const langChainMessages = getLangChainMessages(state.conversation.messages ?? []); const messages = langChainMessages.slice(0, -1); // all but the last message return { + ...state, conversation: state.conversation, messages, }; @@ -77,7 +78,7 @@ export const persistConversationChanges = async ({ }); if (!updatedConversation) { logger.debug('Not updated conversation'); - return { conversation: undefined, messages: [] }; + return { ...state, conversation: undefined, messages: [] }; } logger.debug(`conversationId: ${conversationId}`); @@ -85,6 +86,7 @@ export const persistConversationChanges = async ({ const messages = langChainMessages.slice(0, -1); // all but the last message return { + ...state, conversation: updatedConversation, messages, }; diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/run_agent.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/run_agent.ts index aeca4dca21ea6..8529d25461f53 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/run_agent.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/run_agent.ts @@ -21,7 +21,6 @@ export const AGENT_NODE = 'agent'; export const AGENT_NODE_TAG = 'agent_run'; -const NO_HISTORY = '[No existing knowledge history]'; /** * Node to run the agent * @@ -40,21 +39,15 @@ export const runAgent = async ({ }: RunAgentParams) => { logger.debug(() => `Node state:\n${JSON.stringify(state, null, 2)}`); - const knowledgeHistory = await dataClients?.kbDataClient?.getKnowledgeBaseDocuments({ - kbResource: 'user', - required: true, - query: '', - }); - const agentOutcome = await agentRunnable.withConfig({ tags: [AGENT_NODE_TAG] }).invoke( { ...state, chat_history: state.messages, // TODO: Message de-dupe with ...state spread - knowledge_history: JSON.stringify(knowledgeHistory?.length ? knowledgeHistory : NO_HISTORY), }, config ); return { + ...state, agentOutcome, }; }; diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/prompts.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/prompts.ts index 83eba779e2352..97f8f014cb82f 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/prompts.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/prompts.ts @@ -8,10 +8,7 @@ import { ChatPromptTemplate } from '@langchain/core/prompts'; export const openAIFunctionAgentPrompt = ChatPromptTemplate.fromMessages([ - [ - 'system', - 'You are a helpful assistant\n\nUse the below context as a sample of information about the user from their knowledge base:\n\n```{knowledge_history}```', - ], + ['system', 'You are a helpful assistant'], ['placeholder', '{chat_history}'], ['human', '{input}'], ['placeholder', '{agent_scratchpad}'], @@ -52,8 +49,5 @@ export const structuredChatAgentPrompt = ChatPromptTemplate.fromMessages([ 'Begin! Reminder to ALWAYS respond with a valid json blob of a single action with no additional output. When using tools, ALWAYS input the expected JSON schema args. Your answer will be parsed as JSON, so never use double quotes within the output and instead use backticks. Single quotes may be used, such as apostrophes. Response format is Action:```$JSON_BLOB```then Observation', ], ['placeholder', '{chat_history}'], - [ - 'human', - 'Use the below context as a sample of information about the user from their knowledge base:\n\n```\n{knowledge_history}\n```\n\n{input}\n\n{agent_scratchpad}\n(reminder to respond in a JSON blob with no additional output no matter what)', - ], + ['human', '{input}\n\n{agent_scratchpad}\n\n(reminder to respond in a JSON blob no matter what)'], ]); 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 d938310e91d6d..b27105abf8180 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 @@ -71,26 +71,12 @@ export const KNOWLEDGE_BASE_EXECUTION_ERROR_EVENT: EventTypeOpts<{ }; export const INVOKE_ASSISTANT_SUCCESS_EVENT: EventTypeOpts<{ - isEnabledKnowledgeBase: boolean; - isEnabledRAGAlerts: boolean; assistantStreamingEnabled: boolean; actionTypeId: string; model?: string; }> = { eventType: 'invoke_assistant_success', schema: { - isEnabledKnowledgeBase: { - type: 'boolean', - _meta: { - description: 'Is Knowledge Base enabled', - }, - }, - isEnabledRAGAlerts: { - type: 'boolean', - _meta: { - description: 'Is RAG Alerts enabled', - }, - }, assistantStreamingEnabled: { type: 'boolean', _meta: { @@ -115,8 +101,6 @@ export const INVOKE_ASSISTANT_SUCCESS_EVENT: EventTypeOpts<{ export const INVOKE_ASSISTANT_ERROR_EVENT: EventTypeOpts<{ errorMessage: string; - isEnabledKnowledgeBase: boolean; - isEnabledRAGAlerts: boolean; assistantStreamingEnabled: boolean; actionTypeId: string; model?: string; @@ -129,18 +113,6 @@ export const INVOKE_ASSISTANT_ERROR_EVENT: EventTypeOpts<{ description: 'Error message from Elasticsearch', }, }, - isEnabledKnowledgeBase: { - type: 'boolean', - _meta: { - description: 'Is Knowledge Base enabled', - }, - }, - isEnabledRAGAlerts: { - type: 'boolean', - _meta: { - description: 'Is RAG Alerts enabled', - }, - }, assistantStreamingEnabled: { type: 'boolean', _meta: { diff --git a/x-pack/plugins/elastic_assistant/server/routes/chat/chat_complete_route.test.ts b/x-pack/plugins/elastic_assistant/server/routes/chat/chat_complete_route.test.ts index a487e56019bd8..0b05bb2875cb6 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/chat/chat_complete_route.test.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/chat/chat_complete_route.test.ts @@ -5,27 +5,26 @@ * 2.0. */ -import { ElasticsearchClient, IRouter, KibanaRequest, Logger } from '@kbn/core/server'; -import type { ActionsClient } from '@kbn/actions-plugin/server'; -import { BaseMessage } from '@langchain/core/messages'; +import { IRouter } from '@kbn/core/server'; import { NEVER } from 'rxjs'; import { mockActionResponse } from '../../__mocks__/action_result_data'; import { ElasticAssistantRequestHandlerContext } from '../../types'; import { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks'; import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { coreMock } from '@kbn/core/server/mocks'; -import { - INVOKE_ASSISTANT_ERROR_EVENT, - INVOKE_ASSISTANT_SUCCESS_EVENT, -} from '../../lib/telemetry/event_based_telemetry'; +import { INVOKE_ASSISTANT_ERROR_EVENT } from '../../lib/telemetry/event_based_telemetry'; import { PassThrough } from 'stream'; import { getConversationResponseMock } from '../../ai_assistant_data_clients/conversations/update_conversation.test'; import { actionsClientMock } from '@kbn/actions-plugin/server/actions_client/actions_client.mock'; import { getFindAnonymizationFieldsResultWithSingleHit } from '../../__mocks__/response'; import { defaultAssistantFeatures } from '@kbn/elastic-assistant-common'; import { chatCompleteRoute } from './chat_complete_route'; -import { PublicMethodsOf } from '@kbn/utility-types'; import { licensingMock } from '@kbn/licensing-plugin/server/mocks'; +import { + appendAssistantMessageToConversation, + createConversationWithUserInput, + langChainExecute, +} from '../helpers'; const license = licensingMock.createLicenseMock(); @@ -33,43 +32,12 @@ const actionsClient = actionsClientMock.create(); jest.mock('../../lib/build_response', () => ({ buildResponse: jest.fn().mockImplementation((x) => x), })); +jest.mock('../helpers'); +const mockAppendAssistantMessageToConversation = appendAssistantMessageToConversation as jest.Mock; + +const mockLangChainExecute = langChainExecute as jest.Mock; const mockStream = jest.fn().mockImplementation(() => new PassThrough()); -jest.mock('../../lib/langchain/execute_custom_llm_chain', () => ({ - callAgentExecutor: jest.fn().mockImplementation( - async ({ - connectorId, - isStream, - onLlmResponse, - }: { - onLlmResponse: ( - content: string, - replacements: Record, - isError: boolean - ) => Promise; - actionsClient: PublicMethodsOf; - connectorId: string; - esClient: ElasticsearchClient; - langChainMessages: BaseMessage[]; - logger: Logger; - isStream: boolean; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - request: KibanaRequest; - }) => { - if (!isStream && connectorId === 'mock-connector-id') { - return { - connector_id: 'mock-connector-id', - data: mockActionResponse, - status: 'ok', - }; - } else if (isStream && connectorId === 'mock-connector-id') { - return mockStream; - } else { - onLlmResponse('simulated error', {}, true).catch(() => {}); - throw new Error('simulated error'); - } - } - ), -})); + const existingConversation = getConversationResponseMock(); const reportEvent = jest.fn(); const appendConversationMessages = jest.fn(); @@ -103,6 +71,13 @@ const mockContext = { appendConversationMessages: appendConversationMessages.mockResolvedValue(existingConversation), }), + getAIAssistantKnowledgeBaseDataClient: jest.fn().mockResolvedValue({ + getKnowledgeBaseDocuments: jest.fn().mockResolvedValue([]), + indexTemplateAndPattern: { + alias: 'knowledge-base-alias', + }, + isModelDeployed: jest.fn().mockResolvedValue(true), + }), getAIAssistantAnonymizationFieldsDataClient: jest.fn().mockResolvedValue({ findDocuments: jest.fn().mockResolvedValue(getFindAnonymizationFieldsResultWithSingleHit()), }), @@ -125,8 +100,6 @@ const mockRequest = { conversationId: 'mock-conversation-id', connectorId: 'mock-connector-id', persist: true, - isEnabledKnowledgeBase: true, - isEnabledRAGAlerts: false, model: 'gpt-4', messages: [ { @@ -164,7 +137,37 @@ describe('chatCompleteRoute', () => { beforeEach(() => { jest.clearAllMocks(); + mockAppendAssistantMessageToConversation.mockResolvedValue(true); license.hasAtLeast.mockReturnValue(true); + (createConversationWithUserInput as jest.Mock).mockResolvedValue({ id: 'something' }); + mockLangChainExecute.mockImplementation( + async ({ + connectorId, + isStream, + onLlmResponse, + }: { + connectorId: string; + isStream: boolean; + onLlmResponse: ( + content: string, + replacements: Record, + isError: boolean + ) => Promise; + }) => { + if (!isStream && connectorId === 'mock-connector-id') { + return { + connector_id: 'mock-connector-id', + data: mockActionResponse, + status: 'ok', + }; + } else if (isStream && connectorId === 'mock-connector-id') { + return mockStream; + } else { + onLlmResponse('simulated error', {}, true).catch(() => {}); + throw new Error('simulated error'); + } + } + ); actionsClient.execute.mockImplementation( jest.fn().mockResolvedValue(() => ({ data: 'mockChatCompletion', @@ -256,72 +259,6 @@ describe('chatCompleteRoute', () => { ); }); - it('reports success events to telemetry - kb on, RAG alerts off', async () => { - const mockRouter = { - versioned: { - post: jest.fn().mockImplementation(() => { - return { - addVersion: jest.fn().mockImplementation(async (_, handler) => { - await handler(mockContext, mockRequest, mockResponse); - - expect(reportEvent).toHaveBeenCalledWith(INVOKE_ASSISTANT_SUCCESS_EVENT.eventType, { - isEnabledKnowledgeBase: true, - isEnabledRAGAlerts: false, - actionTypeId: '.gen-ai', - model: 'gpt-4', - assistantStreamingEnabled: false, - }); - }), - }; - }), - }, - }; - - await chatCompleteRoute( - mockRouter as unknown as IRouter, - mockGetElser - ); - }); - - it('reports success events to telemetry - kb on, RAG alerts on', async () => { - const ragRequest = { - ...mockRequest, - body: { - ...mockRequest.body, - isEnabledRAGAlerts: true, - anonymizationFields: [ - { id: '@timestamp', field: '@timestamp', allowed: true, anonymized: false }, - { id: 'host.name', field: 'host.name', allowed: true, anonymized: true }, - ], - }, - }; - - const mockRouter = { - versioned: { - post: jest.fn().mockImplementation(() => { - return { - addVersion: jest.fn().mockImplementation(async (_, handler) => { - await handler(mockContext, ragRequest, mockResponse); - - expect(reportEvent).toHaveBeenCalledWith(INVOKE_ASSISTANT_SUCCESS_EVENT.eventType, { - isEnabledKnowledgeBase: true, - isEnabledRAGAlerts: true, - actionTypeId: '.gen-ai', - model: 'gpt-4', - assistantStreamingEnabled: false, - }); - }), - }; - }), - }, - }; - - await chatCompleteRoute( - mockRouter as unknown as IRouter, - mockGetElser - ); - }); - it('reports error events to telemetry - kb on, RAG alerts off', async () => { const requestWithBadConnectorId = { ...mockRequest, @@ -340,8 +277,6 @@ describe('chatCompleteRoute', () => { expect(reportEvent).toHaveBeenCalledWith(INVOKE_ASSISTANT_ERROR_EVENT.eventType, { errorMessage: 'simulated error', - isEnabledKnowledgeBase: true, - isEnabledRAGAlerts: true, actionTypeId: '.gen-ai', model: 'gpt-4', assistantStreamingEnabled: false, @@ -363,7 +298,7 @@ describe('chatCompleteRoute', () => { ...mockRequest, body: { ...mockRequest.body, - conversationId: '99999', + conversationId: undefined, connectorId: 'bad-connector-id', }, }; @@ -374,11 +309,10 @@ describe('chatCompleteRoute', () => { return { addVersion: jest.fn().mockImplementation(async (_, handler) => { await handler(mockContext, badRequest, mockResponse); - expect(appendConversationMessages.mock.calls[1][0].messages[0]).toEqual( + expect(mockAppendAssistantMessageToConversation).toHaveBeenCalledWith( expect.objectContaining({ - content: 'simulated error', + messageContent: 'simulated error', isError: true, - role: 'assistant', }) ); }), diff --git a/x-pack/plugins/elastic_assistant/server/routes/chat/chat_complete_route.ts b/x-pack/plugins/elastic_assistant/server/routes/chat/chat_complete_route.ts index 10da330a36c79..b8f75e2376863 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/chat/chat_complete_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/chat/chat_complete_route.ts @@ -23,10 +23,8 @@ import { INVOKE_ASSISTANT_ERROR_EVENT } from '../../lib/telemetry/event_based_te import { ElasticAssistantPluginRouter, GetElser } from '../../types'; import { buildResponse } from '../../lib/build_response'; import { - DEFAULT_PLUGIN_NAME, appendAssistantMessageToConversation, - createOrUpdateConversationWithUserInput, - getPluginNameFromRequest, + createConversationWithUserInput, langChainExecute, performChecks, } from '../helpers'; @@ -150,41 +148,21 @@ export const chatCompleteRoute = ( return transformedMessage; }); - let updatedConversation: ConversationResponse | undefined | null; - // Fetch any tools registered by the request's originating plugin - const pluginName = getPluginNameFromRequest({ - request, - defaultPluginName: DEFAULT_PLUGIN_NAME, - logger, - }); - const enableKnowledgeBaseByDefault = - ctx.elasticAssistant.getRegisteredFeatures(pluginName).assistantKnowledgeBaseByDefault; - // TODO: remove non-graph persistance when KB will be enabled by default - if ( - (!enableKnowledgeBaseByDefault || (enableKnowledgeBaseByDefault && !conversationId)) && - request.body.persist && - conversationsDataClient - ) { - updatedConversation = await createOrUpdateConversationWithUserInput({ - actionsClient, + let newConversation: ConversationResponse | undefined | null; + if (conversationsDataClient && !conversationId && request.body.persist) { + newConversation = await createConversationWithUserInput({ actionTypeId, connectorId, conversationId, conversationsDataClient, promptId: request.body.promptId, - logger, replacements: latestReplacements, newMessages: messages, model: request.body.model, }); - if (updatedConversation == null) { - return assistantResponse.error({ - body: `conversation id: "${conversationId}" not updated`, - statusCode: 400, - }); - } + // messages are anonymized by conversationsDataClient - messages = updatedConversation?.messages?.map((c) => ({ + messages = newConversation?.messages?.map((c) => ({ role: c.role, content: c.content, })); @@ -195,9 +173,9 @@ export const chatCompleteRoute = ( traceData: Message['traceData'] = {}, isError = false ): Promise => { - if (updatedConversation?.id && conversationsDataClient) { + if (newConversation?.id && conversationsDataClient) { await appendAssistantMessageToConversation({ - conversationId: updatedConversation?.id, + conversationId: newConversation?.id, conversationsDataClient, messageContent: content, replacements: latestReplacements, @@ -209,12 +187,11 @@ export const chatCompleteRoute = ( return await langChainExecute({ abortSignal, - isEnabledKnowledgeBase: true, isStream: request.body.isStream ?? false, actionsClient, actionTypeId, connectorId, - conversationId, + conversationId: conversationId ?? newConversation?.id, context: ctx, getElser, logger, @@ -222,7 +199,16 @@ export const chatCompleteRoute = ( onLlmResponse, onNewReplacements, replacements: latestReplacements, - request, + request: { + ...request, + // TODO: clean up after empty tools will be available to use + body: { + ...request.body, + replacements: {}, + size: 10, + alertsIndexPattern: '.alerts-security.alerts-default', + }, + }, response, telemetry, responseLanguage: request.body.responseLanguage, @@ -231,8 +217,6 @@ export const chatCompleteRoute = ( const error = transformError(err as Error); telemetry?.reportEvent(INVOKE_ASSISTANT_ERROR_EVENT.eventType, { actionTypeId: actionTypeId ?? '', - isEnabledKnowledgeBase: true, - isEnabledRAGAlerts: true, model: request.body.model, errorMessage: error.message, // TODO rm actionTypeId check when llmClass for bedrock streaming is implemented 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 79b601ed01073..14a530e5526c2 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 @@ -153,8 +153,6 @@ export const postEvaluateRoute = ( actionTypeId: '.gen-ai', replacements: {}, size: DEFAULT_SIZE, - isEnabledKnowledgeBase: true, - isEnabledRAGAlerts: true, conversationId: '', }, }; @@ -164,7 +162,7 @@ export const postEvaluateRoute = ( const enableKnowledgeBaseByDefault = assistantContext.getRegisteredFeatures(pluginName).assistantKnowledgeBaseByDefault; const kbDataClient = enableKnowledgeBaseByDefault - ? (await assistantContext.getAIAssistantKnowledgeBaseDataClient(false)) ?? undefined + ? (await assistantContext.getAIAssistantKnowledgeBaseDataClient()) ?? undefined : undefined; const kbIndex = enableKnowledgeBaseByDefault && kbDataClient != null @@ -194,7 +192,6 @@ export const postEvaluateRoute = ( agentEvaluator: async (langChainMessages, exampleId) => { const evalResult = await AGENT_EXECUTOR_MAP[agentName]({ actionsClient, - isEnabledKnowledgeBase: true, assistantTools, connectorId, esClient, diff --git a/x-pack/plugins/elastic_assistant/server/routes/helpers.ts b/x-pack/plugins/elastic_assistant/server/routes/helpers.ts index a8fe0d0c25d68..2bf0cacd53963 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/helpers.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/helpers.ts @@ -29,8 +29,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 { MINIMUM_AI_ASSISTANT_LICENSE } from '../../common/constants'; -import { ESQL_RESOURCE, KNOWLEDGE_BASE_INDEX_PATTERN } from './knowledge_base/constants'; -import { callAgentExecutor } from '../lib/langchain/execute_custom_llm_chain'; +import { ESQL_RESOURCE } from './knowledge_base/constants'; import { buildResponse, getLlmType } from './utils'; import { AgentExecutorParams, @@ -275,57 +274,10 @@ export interface NonLangChainExecuteParams { response: KibanaResponseFactory; telemetry: AnalyticsServiceSetup; } -export const nonLangChainExecute = async ({ - messages, - abortSignal, - actionTypeId, - connectorId, - logger, - actionsClient, - onLlmResponse, - response, - request, - telemetry, -}: NonLangChainExecuteParams) => { - logger.debug('Executing via actions framework directly'); - const result = await executeAction({ - abortSignal, - onLlmResponse, - actionsClient, - connectorId, - actionTypeId, - params: { - subAction: request.body.subAction, - subActionParams: { - model: request.body.model, - messages, - ...(actionTypeId === '.gen-ai' - ? { n: 1, stop: null, temperature: 0.2 } - : { temperature: 0, stopSequences: [] }), - }, - }, - logger, - }); - - telemetry.reportEvent(INVOKE_ASSISTANT_SUCCESS_EVENT.eventType, { - actionTypeId, - isEnabledKnowledgeBase: request.body.isEnabledKnowledgeBase, - isEnabledRAGAlerts: request.body.isEnabledRAGAlerts, - model: request.body.model, - assistantStreamingEnabled: request.body.subAction !== 'invokeAI', - }); - return response.ok({ - body: result, - ...(request.body.subAction === 'invokeAI' - ? { headers: { 'content-type': 'application/json' } } - : {}), - }); -}; export interface LangChainExecuteParams { messages: Array>; replacements: Replacements; - isEnabledKnowledgeBase: boolean; isStream?: boolean; onNewReplacements: (newReplacements: Replacements) => void; abortSignal: AbortSignal; @@ -353,7 +305,6 @@ export const langChainExecute = async ({ messages, replacements, onNewReplacements, - isEnabledKnowledgeBase, abortSignal, telemetry, actionTypeId, @@ -369,10 +320,6 @@ export const langChainExecute = async ({ responseLanguage, isStream = true, }: LangChainExecuteParams) => { - // TODO: Add `traceId` to actions request when calling via langchain - logger.debug( - `Executing via langchain, isEnabledKnowledgeBase: ${isEnabledKnowledgeBase}, isEnabledRAGAlerts: ${request.body.isEnabledRAGAlerts}` - ); // Fetch any tools registered by the request's originating plugin const pluginName = getPluginNameFromRequest({ request, @@ -397,19 +344,11 @@ export const langChainExecute = async ({ const conversationsDataClient = await assistantContext.getAIAssistantConversationsDataClient(); // Create an ElasticsearchStore for KB interactions - // Setup with kbDataClient if `assistantKnowledgeBaseByDefault` FF is enabled - const enableKnowledgeBaseByDefault = - assistantContext.getRegisteredFeatures(pluginName).assistantKnowledgeBaseByDefault; - const kbDataClient = enableKnowledgeBaseByDefault - ? (await assistantContext.getAIAssistantKnowledgeBaseDataClient(false)) ?? undefined - : undefined; - const kbIndex = - enableKnowledgeBaseByDefault && kbDataClient != null - ? kbDataClient.indexTemplateAndPattern.alias - : KNOWLEDGE_BASE_INDEX_PATTERN; + const kbDataClient = + (await assistantContext.getAIAssistantKnowledgeBaseDataClient()) ?? undefined; const esStore = new ElasticsearchStore( esClient, - kbIndex, + kbDataClient?.indexTemplateAndPattern?.alias ?? '', logger, telemetry, elserId, @@ -429,7 +368,6 @@ export const langChainExecute = async ({ dataClients, alertsIndexPattern: request.body.alertsIndexPattern, actionsClient, - isEnabledKnowledgeBase, assistantTools, conversationId, connectorId, @@ -455,18 +393,12 @@ export const langChainExecute = async ({ }, }; - // New code path for LangGraph implementation, behind `assistantKnowledgeBaseByDefault` FF - let result: StreamResponseWithHeaders | StaticReturnType; - if (enableKnowledgeBaseByDefault && request.body.isEnabledKnowledgeBase) { - result = await callAssistantGraph(executorParams); - } else { - result = await callAgentExecutor(executorParams); - } + const result: StreamResponseWithHeaders | StaticReturnType = await callAssistantGraph( + executorParams + ); telemetry.reportEvent(INVOKE_ASSISTANT_SUCCESS_EVENT.eventType, { actionTypeId, - isEnabledKnowledgeBase, - isEnabledRAGAlerts: request.body.isEnabledRAGAlerts ?? true, model: request.body.model, // TODO rm actionTypeId check when llmClass for bedrock streaming is implemented // tracked here: https://github.com/elastic/security-team/issues/7363 @@ -475,76 +407,47 @@ export const langChainExecute = async ({ return response.ok(result); }; -export interface CreateOrUpdateConversationWithParams { - logger: Logger; +export interface CreateConversationWithParams { conversationsDataClient: AIAssistantConversationsDataClient; replacements: Replacements; conversationId?: string; promptId?: string; actionTypeId: string; connectorId: string; - actionsClient: PublicMethodsOf; newMessages?: Array>; model?: string; - responseLanguage?: string; } -export const createOrUpdateConversationWithUserInput = async ({ - logger, +export const createConversationWithUserInput = async ({ conversationsDataClient, replacements, conversationId, actionTypeId, promptId, connectorId, - actionsClient, newMessages, model, - responseLanguage, -}: CreateOrUpdateConversationWithParams) => { +}: CreateConversationWithParams) => { if (!conversationId) { if (newMessages && newMessages.length > 0) { - const title = await generateTitleForNewChatConversation({ - message: newMessages[0], - actionsClient, - actionTypeId, - connectorId, - logger, - model, - responseLanguage, - }); - if (title) { - return conversationsDataClient.createConversation({ - conversation: { - title, - messages: newMessages.map((m) => ({ - content: m.content, - role: m.role, - timestamp: new Date().toISOString(), - })), - replacements, - apiConfig: { - connectorId, - actionTypeId, - model, - defaultSystemPromptId: promptId, - }, + return conversationsDataClient.createConversation({ + conversation: { + title: NEW_CHAT, + messages: newMessages.map((m) => ({ + content: m.content, + role: m.role, + timestamp: new Date().toISOString(), + })), + replacements, + apiConfig: { + connectorId, + actionTypeId, + model, + defaultSystemPromptId: promptId, }, - }); - } + }, + }); } - return; } - return updateConversationWithUserInput({ - actionsClient, - actionTypeId, - connectorId, - conversationId, - conversationsDataClient, - logger, - replacements, - newMessages, - model, - }); }; export interface UpdateConversationWithParams { diff --git a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/delete_knowledge_base.test.ts b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/delete_knowledge_base.test.ts deleted file mode 100644 index ad130cddc5560..0000000000000 --- a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/delete_knowledge_base.test.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { deleteKnowledgeBaseRoute } from './delete_knowledge_base'; -import { serverMock } from '../../__mocks__/server'; -import { requestContextMock } from '../../__mocks__/request_context'; -import { getDeleteKnowledgeBaseRequest } from '../../__mocks__/request'; -import { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks'; - -describe('Delete Knowledge Base Route', () => { - let server: ReturnType; - // eslint-disable-next-line prefer-const - let { clients, context } = requestContextMock.createTools(); - - clients.core.elasticsearch.client = elasticsearchServiceMock.createScopedClusterClient(); - - beforeEach(() => { - server = serverMock.create(); - ({ context } = requestContextMock.createTools()); - - deleteKnowledgeBaseRoute(server.router); - }); - - describe('Status codes', () => { - test('returns 200 if base resources are deleted', async () => { - const response = await server.inject( - getDeleteKnowledgeBaseRequest(), - requestContextMock.convertContext(context) - ); - - expect(response.status).toEqual(200); - }); - - test('returns 500 if error is thrown when deleting resources', async () => { - context.core.elasticsearch.client.asInternalUser.indices.delete.mockRejectedValue( - new Error('Test error') - ); - const response = await server.inject( - getDeleteKnowledgeBaseRequest('esql'), - requestContextMock.convertContext(context) - ); - - expect(response.status).toEqual(500); - }); - }); -}); diff --git a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/delete_knowledge_base.ts b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/delete_knowledge_base.ts index 6e81738a7376f..4352c866a19c1 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/delete_knowledge_base.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/delete_knowledge_base.ts @@ -20,8 +20,7 @@ import { buildRouteValidationWithZod } from '@kbn/elastic-assistant-common/impl/ import { buildResponse } from '../../lib/build_response'; import { ElasticAssistantRequestHandlerContext } from '../../types'; import { ElasticsearchStore } from '../../lib/langchain/elasticsearch_store/elasticsearch_store'; -import { ESQL_RESOURCE, KNOWLEDGE_BASE_INDEX_PATTERN } from './constants'; -import { DEFAULT_PLUGIN_NAME, getPluginNameFromRequest } from '../helpers'; +import { ESQL_RESOURCE } from './constants'; import { getKbResource } from './get_kb_resource'; /** @@ -53,43 +52,26 @@ export const deleteKnowledgeBaseRoute = ( const assistantContext = await context.elasticAssistant; const logger = assistantContext.logger; const telemetry = assistantContext.telemetry; - const pluginName = getPluginNameFromRequest({ - request, - defaultPluginName: DEFAULT_PLUGIN_NAME, - logger, - }); - const enableKnowledgeBaseByDefault = - assistantContext.getRegisteredFeatures(pluginName).assistantKnowledgeBaseByDefault; try { const kbResource = getKbResource(request); - const esClient = (await context.core).elasticsearch.client.asInternalUser; - let esStore = new ElasticsearchStore( + + const knowledgeBaseDataClient = + await assistantContext.getAIAssistantKnowledgeBaseDataClient(); + if (!knowledgeBaseDataClient) { + return response.custom({ body: { success: false }, statusCode: 500 }); + } + const esStore = new ElasticsearchStore( esClient, - KNOWLEDGE_BASE_INDEX_PATTERN, + knowledgeBaseDataClient.indexTemplateAndPattern.alias, logger, - telemetry + telemetry, + 'elserId', // Not needed for delete ops + kbResource, + knowledgeBaseDataClient ); - // Code path for when `assistantKnowledgeBaseByDefault` FF is enabled, only need an esStore w/ kbDataClient - if (enableKnowledgeBaseByDefault) { - const knowledgeBaseDataClient = - await assistantContext.getAIAssistantKnowledgeBaseDataClient(false); - if (!knowledgeBaseDataClient) { - return response.custom({ body: { success: false }, statusCode: 500 }); - } - esStore = new ElasticsearchStore( - esClient, - knowledgeBaseDataClient.indexTemplateAndPattern.alias, - logger, - telemetry, - 'elserId', // Not needed for delete ops - kbResource, - knowledgeBaseDataClient - ); - } - if (kbResource === ESQL_RESOURCE) { // For now, tearing down the Knowledge Base is fine, but will want to support removing specific assets based // on resource name or document query 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 f5fd6305c8b4b..22543a21973ce 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 @@ -166,9 +166,7 @@ export const bulkActionKnowledgeBaseEntriesRoute = (router: ElasticAssistantPlug // subscribing to completed$, because it handles both cases when request was completed and aborted. // when route is finished by timeout, aborted$ is not getting fired request.events.completed$.subscribe(() => abortController.abort()); - const kbDataClient = await ctx.elasticAssistant.getAIAssistantKnowledgeBaseDataClient( - false - ); + const kbDataClient = await ctx.elasticAssistant.getAIAssistantKnowledgeBaseDataClient(); const spaceId = ctx.elasticAssistant.getSpaceId(); // Authenticated user null check completed in `performChecks()` above const authenticatedUser = ctx.elasticAssistant.getCurrentUser() as AuthenticatedUser; 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 2d7bdb93ad2e1..009ad189708aa 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 @@ -67,9 +67,7 @@ export const createKnowledgeBaseEntryRoute = (router: ElasticAssistantPluginRout pageContent: request.body.text, }, ]; - const kbDataClient = await ctx.elasticAssistant.getAIAssistantKnowledgeBaseDataClient( - false - ); + const kbDataClient = await ctx.elasticAssistant.getAIAssistantKnowledgeBaseDataClient(); const createResponse = await kbDataClient?.addKnowledgeBaseDocuments({ documents }); if (createResponse == null) { diff --git a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/find_route.ts b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/find_route.ts index 9dc7bb3f39dbf..e939eae1eb3ad 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/find_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/find_route.ts @@ -63,9 +63,7 @@ export const findKnowledgeBaseEntriesRoute = (router: ElasticAssistantPluginRout return checkResponse; } - const kbDataClient = await ctx.elasticAssistant.getAIAssistantKnowledgeBaseDataClient( - false - ); + const kbDataClient = await ctx.elasticAssistant.getAIAssistantKnowledgeBaseDataClient(); const currentUser = ctx.elasticAssistant.getCurrentUser(); const additionalFilter = query.filter ? ` AND ${query.filter}` : ''; diff --git a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/get_knowledge_base_status.test.ts b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/get_knowledge_base_status.test.ts index ba8992d9c19bd..569016d3c0359 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/get_knowledge_base_status.test.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/get_knowledge_base_status.test.ts @@ -32,6 +32,13 @@ describe('Get Knowledge Base Status Route', () => { server = serverMock.create(); ({ context } = requestContextMock.createTools()); context.elasticAssistant.getCurrentUser.mockReturnValue(mockUser); + context.elasticAssistant.getAIAssistantKnowledgeBaseDataClient = jest.fn().mockResolvedValue({ + getKnowledgeBaseDocuments: jest.fn().mockResolvedValue([]), + indexTemplateAndPattern: { + alias: 'knowledge-base-alias', + }, + isModelInstalled: jest.fn().mockResolvedValue(true), + }); getKnowledgeBaseStatusRoute(server.router, mockGetElser); }); diff --git a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/get_knowledge_base_status.ts b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/get_knowledge_base_status.ts index a8d2e96227d60..920b91546aa22 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/get_knowledge_base_status.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/get_knowledge_base_status.ts @@ -19,8 +19,7 @@ import { getKbResource } from './get_kb_resource'; import { buildResponse } from '../../lib/build_response'; import { ElasticAssistantPluginRouter, GetElser } from '../../types'; import { ElasticsearchStore } from '../../lib/langchain/elasticsearch_store/elasticsearch_store'; -import { ESQL_DOCS_LOADED_QUERY, ESQL_RESOURCE, KNOWLEDGE_BASE_INDEX_PATTERN } from './constants'; -import { DEFAULT_PLUGIN_NAME, getPluginNameFromRequest } from '../helpers'; +import { ESQL_DOCS_LOADED_QUERY, ESQL_RESOURCE } from './constants'; /** * Get the status of the Knowledge Base index, pipeline, and resources (collection of documents) @@ -56,49 +55,27 @@ export const getKnowledgeBaseStatusRoute = ( const telemetry = assistantContext.telemetry; try { + // Use asInternalUser const esClient = (await context.core).elasticsearch.client.asInternalUser; const elserId = await getElser(); const kbResource = getKbResource(request); - let esStore = new ElasticsearchStore( + + const kbDataClient = await assistantContext.getAIAssistantKnowledgeBaseDataClient(); + if (!kbDataClient) { + return response.custom({ body: { success: false }, statusCode: 500 }); + } + + // Use old status checks by overriding esStore to use kbDataClient + const esStore = new ElasticsearchStore( esClient, - KNOWLEDGE_BASE_INDEX_PATTERN, + kbDataClient.indexTemplateAndPattern.alias, logger, telemetry, elserId, - kbResource + kbResource, + kbDataClient ); - const pluginName = getPluginNameFromRequest({ - request, - defaultPluginName: DEFAULT_PLUGIN_NAME, - logger, - }); - const enableKnowledgeBaseByDefault = - assistantContext.getRegisteredFeatures(pluginName).assistantKnowledgeBaseByDefault; - - // Code path for when `assistantKnowledgeBaseByDefault` FF is enabled - let isSetupInProgress = false; - if (enableKnowledgeBaseByDefault) { - const kbDataClient = await assistantContext.getAIAssistantKnowledgeBaseDataClient( - false - ); - if (!kbDataClient) { - return response.custom({ body: { success: false }, statusCode: 500 }); - } - - // Use old status checks by overriding esStore to use kbDataClient - esStore = new ElasticsearchStore( - esClient, - kbDataClient.indexTemplateAndPattern.alias, - logger, - telemetry, - elserId, - kbResource, - kbDataClient - ); - isSetupInProgress = kbDataClient.isSetupInProgress; - } - const indexExists = await esStore.indexExists(); const pipelineExists = await esStore.pipelineExists(); const modelExists = await esStore.isModelInstalled(elserId); @@ -106,7 +83,7 @@ export const getKnowledgeBaseStatusRoute = ( const body: ReadKnowledgeBaseResponse = { elser_exists: modelExists, index_exists: indexExists, - is_setup_in_progress: isSetupInProgress, + is_setup_in_progress: kbDataClient.isSetupInProgress, pipeline_exists: pipelineExists, }; diff --git a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/post_knowledge_base.test.ts b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/post_knowledge_base.test.ts index 547923b5c0d17..7e56561e67915 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/post_knowledge_base.test.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/post_knowledge_base.test.ts @@ -32,6 +32,13 @@ describe('Post Knowledge Base Route', () => { server = serverMock.create(); ({ context } = requestContextMock.createTools()); context.elasticAssistant.getCurrentUser.mockReturnValue(mockUser); + context.elasticAssistant.getAIAssistantKnowledgeBaseDataClient = jest.fn().mockResolvedValue({ + setupKnowledgeBase: jest.fn(), + indexTemplateAndPattern: { + alias: 'knowledge-base-alias', + }, + isModelInstalled: jest.fn().mockResolvedValue(true), + }); postKnowledgeBaseRoute(server.router, mockGetElser); }); @@ -45,17 +52,5 @@ describe('Post Knowledge Base Route', () => { expect(response.status).toEqual(200); }); - - test('returns 500 if error is thrown when creating resources', async () => { - context.core.elasticsearch.client.asInternalUser.indices.exists.mockRejectedValue( - new Error('Test error') - ); - const response = await server.inject( - getPostKnowledgeBaseRequest('esql'), - requestContextMock.convertContext(context) - ); - - expect(response.status).toEqual(500); - }); }); }); diff --git a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/post_knowledge_base.ts b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/post_knowledge_base.ts index bc511d99eb63d..d3b7d6afa1e41 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/post_knowledge_base.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/post_knowledge_base.ts @@ -18,10 +18,7 @@ import { IKibanaResponse, KibanaRequest } from '@kbn/core/server'; import { buildResponse } from '../../lib/build_response'; import { ElasticAssistantPluginRouter, GetElser } from '../../types'; import { ElasticsearchStore } from '../../lib/langchain/elasticsearch_store/elasticsearch_store'; -import { ESQL_DOCS_LOADED_QUERY, ESQL_RESOURCE, KNOWLEDGE_BASE_INDEX_PATTERN } from './constants'; import { getKbResource } from './get_kb_resource'; -import { loadESQL } from '../../lib/langchain/content_loaders/esql_loader'; -import { DEFAULT_PLUGIN_NAME, getPluginNameFromRequest } from '../helpers'; // Since we're awaiting on ELSER setup, this could take a bit (especially if ML needs to autoscale) // Consider just returning if attempt was successful, and switch to client polling @@ -70,79 +67,27 @@ export const postKnowledgeBaseRoute = ( const esClient = core.elasticsearch.client.asInternalUser; const soClient = core.savedObjects.getClient(); - const pluginName = getPluginNameFromRequest({ - request, - defaultPluginName: DEFAULT_PLUGIN_NAME, - logger, - }); - const enableKnowledgeBaseByDefault = - assistantContext.getRegisteredFeatures(pluginName).assistantKnowledgeBaseByDefault; - try { - // Code path for when `assistantKnowledgeBaseByDefault` FF is enabled - if (enableKnowledgeBaseByDefault) { - const knowledgeBaseDataClient = - await assistantContext.getAIAssistantKnowledgeBaseDataClient(true); - if (!knowledgeBaseDataClient) { - return response.custom({ body: { success: false }, statusCode: 500 }); - } - - // Continue to use esStore for loading esql docs until `semantic_text` is available and we can test the new chunking strategy - const esStore = new ElasticsearchStore( - esClient, - knowledgeBaseDataClient.indexTemplateAndPattern.alias, - logger, - telemetry, - elserId, - getKbResource(request), - knowledgeBaseDataClient - ); - - await knowledgeBaseDataClient.setupKnowledgeBase({ esStore, soClient }); - - return response.ok({ body: { success: true } }); + const knowledgeBaseDataClient = + await assistantContext.getAIAssistantKnowledgeBaseDataClient(); + if (!knowledgeBaseDataClient) { + return response.custom({ body: { success: false }, statusCode: 500 }); } - const kbResource = getKbResource(request); + // Continue to use esStore for loading esql docs until `semantic_text` is available and we can test the new chunking strategy const esStore = new ElasticsearchStore( esClient, - KNOWLEDGE_BASE_INDEX_PATTERN, + knowledgeBaseDataClient.indexTemplateAndPattern.alias, logger, telemetry, elserId, - kbResource + getKbResource(request), + knowledgeBaseDataClient ); - // Pre-check on index/pipeline - let indexExists = await esStore.indexExists(); - let pipelineExists = await esStore.pipelineExists(); + await knowledgeBaseDataClient.setupKnowledgeBase({ esStore, soClient }); - // Load if not exists - if (!pipelineExists) { - pipelineExists = await esStore.createPipeline(); - } - if (!indexExists) { - indexExists = await esStore.createIndex(); - } - - // If specific resource is requested, load it - if (kbResource === ESQL_RESOURCE) { - const esqlExists = (await esStore.similaritySearch(ESQL_DOCS_LOADED_QUERY)).length > 0; - if (!esqlExists) { - const loadedKnowledgeBase = await loadESQL(esStore, logger); - return response.custom({ body: { success: loadedKnowledgeBase }, statusCode: 201 }); - } else { - return response.ok({ body: { success: true } }); - } - } - - const wasSuccessful = indexExists && pipelineExists; - - if (wasSuccessful) { - return response.ok({ body: { success: true } }); - } else { - return response.custom({ body: { success: false }, statusCode: 500 }); - } + return response.ok({ body: { success: true } }); } catch (err) { logger.log(err); const error = transformError(err); diff --git a/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.test.ts b/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.test.ts index 91c2cdf18aa9d..12e854d5d0bf3 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.test.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.test.ts @@ -5,9 +5,7 @@ * 2.0. */ -import { ElasticsearchClient, IRouter, KibanaRequest, Logger } from '@kbn/core/server'; -import type { PluginStartContract as ActionsPluginStart } from '@kbn/actions-plugin/server'; -import { BaseMessage } from '@langchain/core/messages'; +import { IRouter, KibanaRequest } from '@kbn/core/server'; import { NEVER } from 'rxjs'; import { mockActionResponse } from '../__mocks__/action_result_data'; import { postActionsConnectorExecuteRoute } from './post_actions_connector_execute'; @@ -15,16 +13,17 @@ import { ElasticAssistantRequestHandlerContext } from '../types'; import { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks'; import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { coreMock } from '@kbn/core/server/mocks'; -import { - INVOKE_ASSISTANT_ERROR_EVENT, - INVOKE_ASSISTANT_SUCCESS_EVENT, -} from '../lib/telemetry/event_based_telemetry'; +import { INVOKE_ASSISTANT_ERROR_EVENT } from '../lib/telemetry/event_based_telemetry'; import { PassThrough } from 'stream'; import { getConversationResponseMock } from '../ai_assistant_data_clients/conversations/update_conversation.test'; import { actionsClientMock } from '@kbn/actions-plugin/server/actions_client/actions_client.mock'; import { getFindAnonymizationFieldsResultWithSingleHit } from '../__mocks__/response'; -import { defaultAssistantFeatures } from '@kbn/elastic-assistant-common'; +import { + defaultAssistantFeatures, + ExecuteConnectorRequestBody, +} from '@kbn/elastic-assistant-common'; import { licensingMock } from '@kbn/licensing-plugin/server/mocks'; +import { appendAssistantMessageToConversation, langChainExecute } from './helpers'; const license = licensingMock.createLicenseMock(); const actionsClient = actionsClientMock.create(); @@ -45,47 +44,9 @@ jest.mock('../lib/executor', () => ({ }), })); const mockStream = jest.fn().mockImplementation(() => new PassThrough()); -jest.mock('../lib/langchain/execute_custom_llm_chain', () => ({ - callAgentExecutor: jest.fn().mockImplementation( - async ({ - connectorId, - isStream, - }: { - actions: ActionsPluginStart; - connectorId: string; - esClient: ElasticsearchClient; - langChainMessages: BaseMessage[]; - logger: Logger; - isStream: boolean; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - request: KibanaRequest; - }) => { - if (!isStream && connectorId === 'mock-connector-id') { - return { - body: { - connector_id: 'mock-connector-id', - data: mockActionResponse, - status: 'ok', - }, - headers: { 'content-type': 'application/json' }, - }; - } else if (isStream && connectorId === 'mock-connector-id') { - return { - body: mockStream, - headers: { - 'Cache-Control': 'no-cache', - Connection: 'keep-alive', - 'Transfer-Encoding': 'chunked', - 'X-Accel-Buffering': 'no', - 'X-Content-Type-Options': 'nosniff', - }, - }; - } else { - throw new Error('simulated error'); - } - } - ), -})); +const mockLangChainExecute = langChainExecute as jest.Mock; +const mockAppendAssistantMessageToConversation = appendAssistantMessageToConversation as jest.Mock; +jest.mock('./helpers'); const existingConversation = getConversationResponseMock(); const reportEvent = jest.fn(); const appendConversationMessages = jest.fn(); @@ -121,6 +82,12 @@ const mockContext = { getAIAssistantAnonymizationFieldsDataClient: jest.fn().mockResolvedValue({ findDocuments: jest.fn().mockResolvedValue(getFindAnonymizationFieldsResultWithSingleHit()), }), + getAIAssistantKnowledgeBaseDataClient: jest.fn().mockResolvedValue({ + getKnowledgeBaseDocuments: jest.fn().mockResolvedValue([]), + indexTemplateAndPattern: { + alias: 'knowledge-base-alias', + }, + }), }, core: { elasticsearch: { @@ -141,8 +108,6 @@ const mockRequest = { subAction: 'invokeAI', message: 'Do you know my name?', actionTypeId: '.gen-ai', - isEnabledKnowledgeBase: true, - isEnabledRAGAlerts: false, replacements: {}, model: 'gpt-4', }, @@ -162,6 +127,40 @@ describe('postActionsConnectorExecuteRoute', () => { beforeEach(() => { jest.clearAllMocks(); license.hasAtLeast.mockReturnValue(true); + mockAppendAssistantMessageToConversation.mockResolvedValue(true); + mockLangChainExecute.mockImplementation( + async ({ + connectorId, + request, + }: { + connectorId: string; + request: KibanaRequest; + }) => { + if (request.body.subAction === 'invokeAI' && connectorId === 'mock-connector-id') { + return { + body: { + connector_id: 'mock-connector-id', + data: mockActionResponse, + status: 'ok', + }, + headers: { 'content-type': 'application/json' }, + }; + } else if (request.body.subAction !== 'invokeAI' && connectorId === 'mock-connector-id') { + return { + body: mockStream, + headers: { + 'Cache-Control': 'no-cache', + Connection: 'keep-alive', + 'Transfer-Encoding': 'chunked', + 'X-Accel-Buffering': 'no', + 'X-Content-Type-Options': 'nosniff', + }, + }; + } else { + throw new Error('simulated error'); + } + } + ); actionsClient.getBulk.mockResolvedValue([ { id: '1', @@ -180,45 +179,7 @@ describe('postActionsConnectorExecuteRoute', () => { ]); }); - it('returns the expected response when isEnabledKnowledgeBase=false', async () => { - const mockRouter = { - versioned: { - post: jest.fn().mockImplementation(() => { - return { - addVersion: jest.fn().mockImplementation(async (_, handler) => { - const result = await handler( - mockContext, - { - ...mockRequest, - body: { - ...mockRequest.body, - isEnabledKnowledgeBase: false, - }, - }, - mockResponse - ); - - expect(result).toEqual({ - body: { - connector_id: 'mock-connector-id', - data: mockActionResponse, - status: 'ok', - }, - headers: { 'content-type': 'application/json' }, - }); - }), - }; - }), - }, - }; - - await postActionsConnectorExecuteRoute( - mockRouter as unknown as IRouter, - mockGetElser - ); - }); - - it('returns the expected response when isEnabledKnowledgeBase=true', async () => { + it('returns the expected response', async () => { const mockRouter = { versioned: { post: jest.fn().mockImplementation(() => { @@ -275,232 +236,17 @@ describe('postActionsConnectorExecuteRoute', () => { ); }); - it('reports success events to telemetry - kb on, RAG alerts off', async () => { - const mockRouter = { - versioned: { - post: jest.fn().mockImplementation(() => { - return { - addVersion: jest.fn().mockImplementation(async (_, handler) => { - await handler(mockContext, mockRequest, mockResponse); - - expect(reportEvent).toHaveBeenCalledWith(INVOKE_ASSISTANT_SUCCESS_EVENT.eventType, { - isEnabledKnowledgeBase: true, - isEnabledRAGAlerts: false, - actionTypeId: '.gen-ai', - model: 'gpt-4', - assistantStreamingEnabled: false, - }); - }), - }; - }), - }, - }; - - await postActionsConnectorExecuteRoute( - mockRouter as unknown as IRouter, - mockGetElser - ); - }); - - it('reports success events to telemetry - kb on, RAG alerts on', async () => { - const ragRequest = { - ...mockRequest, - body: { - ...mockRequest.body, - anonymizationFields: [ - { id: '@timestamp', field: '@timestamp', allowed: true, anonymized: false }, - { id: 'host.name', field: 'host.name', allowed: true, anonymized: true }, - ], - replacements: [], - isEnabledRAGAlerts: true, - }, - }; - - const mockRouter = { - versioned: { - post: jest.fn().mockImplementation(() => { - return { - addVersion: jest.fn().mockImplementation(async (_, handler) => { - await handler(mockContext, ragRequest, mockResponse); - - expect(reportEvent).toHaveBeenCalledWith(INVOKE_ASSISTANT_SUCCESS_EVENT.eventType, { - isEnabledKnowledgeBase: true, - isEnabledRAGAlerts: true, - actionTypeId: '.gen-ai', - model: 'gpt-4', - assistantStreamingEnabled: false, - }); - }), - }; - }), - }, - }; - - await postActionsConnectorExecuteRoute( - mockRouter as unknown as IRouter, - mockGetElser - ); - }); - - it('reports success events to telemetry - kb off, RAG alerts on', async () => { - const req = { - ...mockRequest, - body: { - ...mockRequest.body, - isEnabledKnowledgeBase: false, - anonymizationFields: [ - { id: '@timestamp', field: '@timestamp', allowed: true, anonymized: false }, - { id: 'host.name', field: 'host.name', allowed: true, anonymized: true }, - ], - replacements: [], - isEnabledRAGAlerts: true, - }, - }; - - const mockRouter = { - versioned: { - post: jest.fn().mockImplementation(() => { - return { - addVersion: jest.fn().mockImplementation(async (_, handler) => { - await handler(mockContext, req, mockResponse); - - expect(reportEvent).toHaveBeenCalledWith(INVOKE_ASSISTANT_SUCCESS_EVENT.eventType, { - actionTypeId: '.gen-ai', - model: 'gpt-4', - assistantStreamingEnabled: false, - isEnabledKnowledgeBase: false, - isEnabledRAGAlerts: true, - }); - }), - }; - }), - }, - }; - - await postActionsConnectorExecuteRoute( - mockRouter as unknown as IRouter, - mockGetElser - ); - }); - - it('reports success events to telemetry - kb off, RAG alerts off', async () => { - const req = { - ...mockRequest, - body: { - ...mockRequest.body, - isEnabledKnowledgeBase: false, - }, - }; - - const mockRouter = { - versioned: { - post: jest.fn().mockImplementation(() => { - return { - addVersion: jest.fn().mockImplementation(async (_, handler) => { - await handler(mockContext, req, mockResponse); - - expect(reportEvent).toHaveBeenCalledWith(INVOKE_ASSISTANT_SUCCESS_EVENT.eventType, { - actionTypeId: '.gen-ai', - model: 'gpt-4', - assistantStreamingEnabled: false, - isEnabledKnowledgeBase: false, - isEnabledRAGAlerts: false, - }); - }), - }; - }), - }, - }; - - await postActionsConnectorExecuteRoute( - mockRouter as unknown as IRouter, - mockGetElser - ); - }); - - it('reports error events to telemetry - kb on, RAG alerts off', async () => { - const requestWithBadConnectorId = { - ...mockRequest, - params: { connectorId: 'bad-connector-id' }, - }; - - const mockRouter = { - versioned: { - post: jest.fn().mockImplementation(() => { - return { - addVersion: jest.fn().mockImplementation(async (_, handler) => { - await handler(mockContext, requestWithBadConnectorId, mockResponse); - - expect(reportEvent).toHaveBeenCalledWith(INVOKE_ASSISTANT_ERROR_EVENT.eventType, { - errorMessage: 'simulated error', - isEnabledKnowledgeBase: true, - isEnabledRAGAlerts: false, - actionTypeId: '.gen-ai', - model: 'gpt-4', - assistantStreamingEnabled: false, - }); - }), - }; - }), - }, - }; - - await postActionsConnectorExecuteRoute( - mockRouter as unknown as IRouter, - mockGetElser - ); - }); - - it('reports error events to telemetry - kb on, RAG alerts on', async () => { - const badRequest = { - ...mockRequest, - params: { connectorId: 'bad-connector-id' }, - body: { - ...mockRequest.body, - isEnabledRAGAlerts: true, - }, - }; - - const mockRouter = { - versioned: { - post: jest.fn().mockImplementation(() => { - return { - addVersion: jest.fn().mockImplementation(async (_, handler) => { - await handler(mockContext, badRequest, mockResponse); - - expect(reportEvent).toHaveBeenCalledWith(INVOKE_ASSISTANT_ERROR_EVENT.eventType, { - errorMessage: 'simulated error', - isEnabledKnowledgeBase: true, - isEnabledRAGAlerts: true, - actionTypeId: '.gen-ai', - model: 'gpt-4', - assistantStreamingEnabled: false, - }); - }), - }; - }), - }, - }; - - await postActionsConnectorExecuteRoute( - mockRouter as unknown as IRouter, - mockGetElser - ); - }); - - it('reports error events to telemetry - kb off, RAG alerts on', async () => { + it('reports error events to telemetry', async () => { const badRequest = { ...mockRequest, params: { connectorId: 'bad-connector-id' }, body: { ...mockRequest.body, - isEnabledKnowledgeBase: false, anonymizationFields: [ { id: '@timestamp', field: '@timestamp', allowed: true, anonymized: false }, { id: 'host.name', field: 'host.name', allowed: true, anonymized: true }, ], replacements: [], - isEnabledRAGAlerts: true, }, }; @@ -513,8 +259,6 @@ describe('postActionsConnectorExecuteRoute', () => { expect(reportEvent).toHaveBeenCalledWith(INVOKE_ASSISTANT_ERROR_EVENT.eventType, { errorMessage: 'simulated error', - isEnabledKnowledgeBase: false, - isEnabledRAGAlerts: true, actionTypeId: '.gen-ai', model: 'gpt-4', assistantStreamingEnabled: false, @@ -547,11 +291,10 @@ describe('postActionsConnectorExecuteRoute', () => { return { addVersion: jest.fn().mockImplementation(async (_, handler) => { await handler(mockContext, badRequest, mockResponse); - expect(appendConversationMessages.mock.calls[1][0].messages[0]).toEqual( + expect(mockAppendAssistantMessageToConversation).toHaveBeenCalledWith( expect.objectContaining({ - content: 'simulated error', + messageContent: 'simulated error', isError: true, - role: 'assistant', }) ); }), @@ -566,43 +309,6 @@ describe('postActionsConnectorExecuteRoute', () => { ); }); - it('reports error events to telemetry - kb off, RAG alerts off', async () => { - const badRequest = { - ...mockRequest, - params: { connectorId: 'bad-connector-id' }, - body: { - ...mockRequest.body, - isEnabledKnowledgeBase: false, - }, - }; - - const mockRouter = { - versioned: { - post: jest.fn().mockImplementation(() => { - return { - addVersion: jest.fn().mockImplementation(async (_, handler) => { - await handler(mockContext, badRequest, mockResponse); - - expect(reportEvent).toHaveBeenCalledWith(INVOKE_ASSISTANT_ERROR_EVENT.eventType, { - errorMessage: 'simulated error', - isEnabledKnowledgeBase: false, - isEnabledRAGAlerts: false, - actionTypeId: '.gen-ai', - model: 'gpt-4', - assistantStreamingEnabled: false, - }); - }), - }; - }), - }, - }; - - await postActionsConnectorExecuteRoute( - mockRouter as unknown as IRouter, - mockGetElser - ); - }); - it('returns the expected response when subAction=invokeStream and actionTypeId=.gen-ai', async () => { const mockRouter = { versioned: { diff --git a/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.ts b/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.ts index af095dbb47343..c8099e6e7f2fe 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/post_actions_connector_execute.ts @@ -21,14 +21,7 @@ import { INVOKE_ASSISTANT_ERROR_EVENT } from '../lib/telemetry/event_based_telem import { POST_ACTIONS_CONNECTOR_EXECUTE } from '../../common/constants'; import { buildResponse } from '../lib/build_response'; import { ElasticAssistantRequestHandlerContext, GetElser } from '../types'; -import { - DEFAULT_PLUGIN_NAME, - appendAssistantMessageToConversation, - getPluginNameFromRequest, - langChainExecute, - nonLangChainExecute, - updateConversationWithUserInput, -} from './helpers'; +import { appendAssistantMessageToConversation, langChainExecute } from './helpers'; export const postActionsConnectorExecuteRoute = ( router: IRouter, @@ -97,41 +90,6 @@ export const postActionsConnectorExecuteRoute = ( const conversationsDataClient = await assistantContext.getAIAssistantConversationsDataClient(); - // Fetch any tools registered by the request's originating plugin - const pluginName = getPluginNameFromRequest({ - request, - defaultPluginName: DEFAULT_PLUGIN_NAME, - logger, - }); - const isGraphAvailable = - assistantContext.getRegisteredFeatures(pluginName).assistantKnowledgeBaseByDefault && - request.body.isEnabledKnowledgeBase; - - // TODO: remove non-graph persistance when KB will be enabled by default - if (!isGraphAvailable && conversationId && conversationsDataClient) { - const updatedConversation = await updateConversationWithUserInput({ - actionsClient, - actionTypeId, - connectorId, - conversationId, - conversationsDataClient, - logger, - replacements: latestReplacements, - newMessages: newMessage ? [newMessage] : [], - model: request.body.model, - }); - if (updatedConversation == null) { - return response.badRequest({ - body: `conversation id: "${conversationId}" not updated`, - }); - } - // messages are anonymized by conversationsDataClient - messages = updatedConversation?.messages?.map((c) => ({ - role: c.role, - content: c.content, - })); - } - onLlmResponse = async ( content: string, traceData: Message['traceData'] = {}, @@ -149,26 +107,9 @@ export const postActionsConnectorExecuteRoute = ( } }; - if (!request.body.isEnabledKnowledgeBase && !request.body.isEnabledRAGAlerts) { - // if not langchain, call execute action directly and return the response: - return await nonLangChainExecute({ - abortSignal, - actionsClient, - actionTypeId, - connectorId, - logger, - messages: messages ?? [], - onLlmResponse, - request, - response, - telemetry, - }); - } - return await langChainExecute({ abortSignal, isStream: request.body.subAction !== 'invokeAI', - isEnabledKnowledgeBase: request.body.isEnabledKnowledgeBase ?? false, actionsClient, actionTypeId, connectorId, @@ -176,7 +117,7 @@ export const postActionsConnectorExecuteRoute = ( context: ctx, getElser, logger, - messages: (isGraphAvailable && newMessage ? [newMessage] : messages) ?? [], + messages: (newMessage ? [newMessage] : messages) ?? [], onLlmResponse, onNewReplacements, replacements: latestReplacements, @@ -192,8 +133,6 @@ export const postActionsConnectorExecuteRoute = ( } telemetry.reportEvent(INVOKE_ASSISTANT_ERROR_EVENT.eventType, { actionTypeId: request.body.actionTypeId, - isEnabledKnowledgeBase: request.body.isEnabledKnowledgeBase, - isEnabledRAGAlerts: request.body.isEnabledRAGAlerts, model: request.body.model, errorMessage: error.message, assistantStreamingEnabled: request.body.subAction !== 'invokeAI', diff --git a/x-pack/plugins/elastic_assistant/server/routes/request_context_factory.ts b/x-pack/plugins/elastic_assistant/server/routes/request_context_factory.ts index 75b05dced83ec..b98ddfc6ac8f9 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/request_context_factory.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/request_context_factory.ts @@ -81,15 +81,12 @@ export class RequestContextFactory implements IRequestContextFactory { telemetry: core.analytics, - // Note: Due to plugin lifecycle and feature flag registration timing, we need to pass in the feature flag here - // Remove `initializeKnowledgeBase` once 'assistantKnowledgeBaseByDefault' feature flag is removed - getAIAssistantKnowledgeBaseDataClient: memoize((initializeKnowledgeBase = false) => { + getAIAssistantKnowledgeBaseDataClient: memoize(() => { const currentUser = getCurrentUser(); return this.assistantService.createAIAssistantKnowledgeBaseDataClient({ spaceId: getSpaceId(), logger: this.logger, currentUser, - initializeKnowledgeBase, }); }), diff --git a/x-pack/plugins/elastic_assistant/server/routes/user_conversations/bulk_actions_route.ts b/x-pack/plugins/elastic_assistant/server/routes/user_conversations/bulk_actions_route.ts index 0b41061265121..56adf57a9b7a4 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/user_conversations/bulk_actions_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/user_conversations/bulk_actions_route.ts @@ -175,10 +175,13 @@ export const bulkActionConversationsRoute = ( } if (body.create && body.create.length > 0) { + const userFilter = authenticatedUser?.username + ? `name: "${authenticatedUser?.username}"` + : `id: "${authenticatedUser?.profile_uid}"`; const result = await dataClient?.findDocuments({ perPage: 100, page: 1, - filter: `users:{ id: "${authenticatedUser?.profile_uid}" } AND (${body.create + filter: `users:{ ${userFilter} } AND (${body.create .map((c) => `title:${c.title}`) .join(' OR ')})`, fields: ['title'], diff --git a/x-pack/plugins/elastic_assistant/server/routes/user_conversations/create_route.ts b/x-pack/plugins/elastic_assistant/server/routes/user_conversations/create_route.ts index f2f469da15966..f997121f95aa8 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/user_conversations/create_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/user_conversations/create_route.ts @@ -54,12 +54,14 @@ export const createConversationRoute = (router: ElasticAssistantPluginRouter): v } const dataClient = await ctx.elasticAssistant.getAIAssistantConversationsDataClient(); + const currentUser = ctx.elasticAssistant.getCurrentUser(); + const userFilter = currentUser?.username + ? `name: "${currentUser?.username}"` + : `id: "${currentUser?.profile_uid}"`; const result = await dataClient?.findDocuments({ perPage: 100, page: 1, - filter: `users:{ id: "${ - ctx.elasticAssistant.getCurrentUser()?.profile_uid - }" } AND title:${request.body.title}`, + filter: `users:{ ${userFilter} } AND title:${request.body.title}`, fields: ['title'], }); if (result?.data != null && result.total > 0) { diff --git a/x-pack/plugins/elastic_assistant/server/routes/user_conversations/find_route.ts b/x-pack/plugins/elastic_assistant/server/routes/user_conversations/find_route.ts index 6eda3e37645c5..6a2c3afc41374 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/user_conversations/find_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/user_conversations/find_route.ts @@ -58,12 +58,15 @@ export const findUserConversationsRoute = (router: ElasticAssistantPluginRouter) const currentUser = ctx.elasticAssistant.getCurrentUser(); const additionalFilter = query.filter ? ` AND ${query.filter}` : ''; + const userFilter = currentUser?.username + ? `name: "${currentUser?.username}"` + : `id: "${currentUser?.profile_uid}"`; const result = await dataClient?.findDocuments({ perPage: query.per_page, page: query.page, sortField: query.sort_field, sortOrder: query.sort_order, - filter: `users:{ id: "${currentUser?.profile_uid}" }${additionalFilter}`, + filter: `users:{ ${userFilter} }${additionalFilter}`, fields: query.fields, }); diff --git a/x-pack/plugins/elastic_assistant/server/types.ts b/x-pack/plugins/elastic_assistant/server/types.ts index 10bd2a3fe62c6..d9183ac2109bb 100755 --- a/x-pack/plugins/elastic_assistant/server/types.ts +++ b/x-pack/plugins/elastic_assistant/server/types.ts @@ -113,9 +113,7 @@ export interface ElasticAssistantApiRequestHandlerContext { getSpaceId: () => string; getCurrentUser: () => AuthenticatedUser | null; getAIAssistantConversationsDataClient: () => Promise; - getAIAssistantKnowledgeBaseDataClient: ( - initializeKnowledgeBase: boolean - ) => Promise; + getAIAssistantKnowledgeBaseDataClient: () => Promise; getAttackDiscoveryDataClient: () => Promise; getAIAssistantPromptsDataClient: () => Promise; getAIAssistantAnonymizationFieldsDataClient: () => Promise; diff --git a/x-pack/plugins/enterprise_search/public/navigation_tree.ts b/x-pack/plugins/enterprise_search/public/navigation_tree.ts index d5c640fa67b3e..9264bf5de9750 100644 --- a/x-pack/plugins/enterprise_search/public/navigation_tree.ts +++ b/x-pack/plugins/enterprise_search/public/navigation_tree.ts @@ -253,6 +253,14 @@ export const getNavigationTreeDefinition = ({ defaultMessage: 'Enterprise Search', }), }, + { + children: [{ link: 'maps' }, { link: 'canvas' }, { link: 'graph' }], + id: 'otherTools', + renderAs: 'accordion', + title: i18n.translate('xpack.enterpriseSearch.searchNav.otherTools', { + defaultMessage: 'Other tools', + }), + }, ], defaultIsCollapsed: false, icon, diff --git a/x-pack/plugins/enterprise_search/server/plugin.ts b/x-pack/plugins/enterprise_search/server/plugin.ts index ee403e223305f..d5c917443654f 100644 --- a/x-pack/plugins/enterprise_search/server/plugin.ts +++ b/x-pack/plugins/enterprise_search/server/plugin.ts @@ -18,7 +18,7 @@ import { } from '@kbn/core/server'; import { CustomIntegrationsPluginSetup } from '@kbn/custom-integrations-plugin/server'; import { DataPluginStart } from '@kbn/data-plugin/server/plugin'; -import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { GlobalSearchPluginSetup } from '@kbn/global-search-plugin/server'; import type { GuidedOnboardingPluginSetup } from '@kbn/guided-onboarding-plugin/server'; import type { LicensingPluginStart } from '@kbn/licensing-plugin/public'; diff --git a/x-pack/plugins/features/server/index.ts b/x-pack/plugins/features/server/index.ts index 48c292515ed27..4be87f7033fca 100644 --- a/x-pack/plugins/features/server/index.ts +++ b/x-pack/plugins/features/server/index.ts @@ -22,7 +22,7 @@ export type { FeatureElasticsearchPrivileges, } from '../common'; export { KibanaFeature, ElasticsearchFeature } from '../common'; -export type { PluginSetupContract, PluginStartContract } from './plugin'; +export type { FeaturesPluginSetup, FeaturesPluginStart } from './plugin'; export const config: PluginConfigDescriptor> = { schema: ConfigSchema }; export const plugin = async (initializerContext: PluginInitializerContext) => { diff --git a/x-pack/plugins/features/server/mocks.ts b/x-pack/plugins/features/server/mocks.ts index 7fc36b1365110..bb2292a45377f 100644 --- a/x-pack/plugins/features/server/mocks.ts +++ b/x-pack/plugins/features/server/mocks.ts @@ -5,13 +5,13 @@ * 2.0. */ -import { PluginSetupContract, PluginStartContract } from './plugin'; +import { FeaturesPluginSetup, FeaturesPluginStart } from './plugin'; import { featurePrivilegeIterator, subFeaturePrivilegeIterator, } from './feature_privilege_iterator'; -const createSetup = (): jest.Mocked => { +const createSetup = (): jest.Mocked => { return { getKibanaFeatures: jest.fn(), getElasticsearchFeatures: jest.fn(), @@ -23,7 +23,7 @@ const createSetup = (): jest.Mocked => { }; }; -const createStart = (): jest.Mocked => { +const createStart = (): jest.Mocked => { return { getKibanaFeatures: jest.fn(), getElasticsearchFeatures: jest.fn(), diff --git a/x-pack/plugins/features/server/plugin.ts b/x-pack/plugins/features/server/plugin.ts index c6e8cdd96556c..f564c23fd2a40 100644 --- a/x-pack/plugins/features/server/plugin.ts +++ b/x-pack/plugins/features/server/plugin.ts @@ -39,7 +39,7 @@ import { /** * Describes public Features plugin contract returned at the `setup` stage. */ -export interface PluginSetupContract { +export interface FeaturesPluginSetup { registerKibanaFeature(feature: KibanaFeatureConfig): void; registerElasticsearchFeature(feature: ElasticsearchFeatureConfig): void; @@ -81,7 +81,7 @@ export interface PluginSetupContract { subFeaturePrivilegeIterator: SubFeaturePrivilegeIterator; } -export interface PluginStartContract { +export interface FeaturesPluginStart { getElasticsearchFeatures(): ElasticsearchFeature[]; getKibanaFeatures(): KibanaFeature[]; @@ -91,7 +91,7 @@ export interface PluginStartContract { * Represents Features Plugin instance that will be managed by the Kibana plugin system. */ export class FeaturesPlugin - implements Plugin, RecursiveReadonly> + implements Plugin, RecursiveReadonly> { private readonly logger: Logger; private readonly featureRegistry: FeatureRegistry = new FeatureRegistry(); @@ -102,7 +102,7 @@ export class FeaturesPlugin this.logger = this.initializerContext.logger.get(); } - public setup(core: CoreSetup): RecursiveReadonly { + public setup(core: CoreSetup): RecursiveReadonly { defineRoutes({ router: core.http.createRouter(), featureRegistry: this.featureRegistry, @@ -126,7 +126,7 @@ export class FeaturesPlugin }); } - public start(core: CoreStart): RecursiveReadonly { + public start(core: CoreStart): RecursiveReadonly { this.registerOssFeatures(core.savedObjects); const { overrides } = this.initializerContext.config.get(); diff --git a/x-pack/plugins/fields_metadata/README.md b/x-pack/plugins/fields_metadata/README.md index d08b18a029345..ea561c52febce 100755 --- a/x-pack/plugins/fields_metadata/README.md +++ b/x-pack/plugins/fields_metadata/README.md @@ -1,6 +1,6 @@ # Fields Metadata Plugin -The `@kbn/fields-metadata-plugin` is designed to provide a centralized and asynchronous way to consume field metadata across Kibana. This plugin addresses the need for on-demand retrieval of field metadata from static ECS definitions and integration manifests, with the flexibility to extend to additional resolution sources in the future. +The `@kbn/fields-metadata-plugin` is designed to provide a centralized and asynchronous way to consume field metadata across Kibana. This plugin addresses the need for on-demand retrieval of field metadata from static ECS/Metadata definitions and integration manifests, with the flexibility to extend to additional resolution sources in the future. ## Components and Mechanisms diff --git a/x-pack/plugins/fields_metadata/common/fields_metadata/models/fields_metadata_dictionary.ts b/x-pack/plugins/fields_metadata/common/fields_metadata/models/fields_metadata_dictionary.ts index 0ddda927de676..dffc3fd1217b1 100644 --- a/x-pack/plugins/fields_metadata/common/fields_metadata/models/fields_metadata_dictionary.ts +++ b/x-pack/plugins/fields_metadata/common/fields_metadata/models/fields_metadata_dictionary.ts @@ -14,6 +14,10 @@ export type FieldsMetadataMap = Record; export class FieldsMetadataDictionary { private constructor(private readonly fields: FieldsMetadataMap) {} + getFields() { + return this.fields; + } + pick(attributes: FieldAttribute[]): Record { return mapValues(this.fields, (field) => field.pick(attributes)); } diff --git a/x-pack/plugins/fields_metadata/common/fields_metadata/types.ts b/x-pack/plugins/fields_metadata/common/fields_metadata/types.ts index 8a1327e363aad..a2975bffee46a 100644 --- a/x-pack/plugins/fields_metadata/common/fields_metadata/types.ts +++ b/x-pack/plugins/fields_metadata/common/fields_metadata/types.ts @@ -7,10 +7,12 @@ import { EcsFlat } from '@elastic/ecs'; import * as rt from 'io-ts'; +import { MetadataFields } from '../metadata_fields'; export const fieldSourceRT = rt.keyof({ ecs: null, integration: null, + metadata: null, unknown: null, }); @@ -63,6 +65,7 @@ const optionalMetadataPlainRT = rt.partial({ short: rt.string, source: fieldSourceRT, type: rt.string, + documentation_url: rt.string, }); export const partialFieldMetadataPlainRT = rt.intersection([ @@ -80,11 +83,14 @@ export const fieldAttributeRT = rt.union([ rt.keyof(optionalMetadataPlainRT.props), ]); +export type AnyFieldName = string & {}; +export type TMetadataFields = typeof MetadataFields; +export type MetadataFieldName = keyof TMetadataFields; export type TEcsFields = typeof EcsFlat; export type EcsFieldName = keyof TEcsFields; -export type IntegrationFieldName = string; +export type IntegrationFieldName = AnyFieldName; -export type FieldName = EcsFieldName | (IntegrationFieldName & {}); +export type FieldName = MetadataFieldName | EcsFieldName | IntegrationFieldName; export type FieldMetadataPlain = rt.TypeOf; export type PartialFieldMetadataPlain = rt.TypeOf; diff --git a/x-pack/plugins/fields_metadata/common/index.ts b/x-pack/plugins/fields_metadata/common/index.ts index 8daf749f74261..5417ac4de212f 100644 --- a/x-pack/plugins/fields_metadata/common/index.ts +++ b/x-pack/plugins/fields_metadata/common/index.ts @@ -7,6 +7,7 @@ export { fieldMetadataPlainRT } from './fields_metadata/types'; export type { + AnyFieldName, EcsFieldName, FieldAttribute, FieldMetadataPlain, @@ -14,6 +15,7 @@ export type { IntegrationFieldName, PartialFieldMetadataPlain, TEcsFields, + TMetadataFields, } from './fields_metadata/types'; export { FieldMetadata } from './fields_metadata/models/field_metadata'; diff --git a/x-pack/plugins/fields_metadata/common/metadata_fields.ts b/x-pack/plugins/fields_metadata/common/metadata_fields.ts new file mode 100644 index 0000000000000..4def656fc438c --- /dev/null +++ b/x-pack/plugins/fields_metadata/common/metadata_fields.ts @@ -0,0 +1,123 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const MetadataFields = { + _index: { + dashed_name: 'index', + description: + 'The index to which the document belongs. This metadata field specifies the exact index name in which the document is stored.', + example: 'index_1', + flat_name: '_index', + name: '_index', + short: 'The index to which the document belongs.', + type: 'keyword', + documentation_url: + 'https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-index-field.html', + }, + _id: { + dashed_name: 'id', + description: + 'The document’s ID. This unique identifier is used to fetch, update, or delete a document within an index.', + example: '1', + flat_name: '_id', + name: '_id', + short: 'The document’s ID.', + type: 'keyword', + documentation_url: + 'https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-id-field.html', + }, + _source: { + dashed_name: 'source', + description: + 'The original JSON representing the body of the document. This field contains all the source data that was provided at the time of indexing.', + example: '{"user": "John Doe", "message": "Hello"}', + flat_name: '_source', + name: '_source', + short: 'The original JSON representing the body of the document.', + documentation_url: + 'https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-source-field.html', + }, + _size: { + dashed_name: 'size', + description: + 'The size of the _source field in bytes. Provided by the mapper-size plugin, this metadata field helps in understanding the storage impact of the document.', + example: '150', + flat_name: '_size', + name: '_size', + short: 'The size of the _source field in bytes, provided by the mapper-size plugin.', + documentation_url: + 'https://www.elastic.co/guide/en/elasticsearch/plugins/current/mapper-size.html', + }, + _doc_count: { + dashed_name: 'doc_count', + description: + 'A custom field used for storing document counts when a document represents pre-aggregated data. It helps in scenarios involving pre-computed data aggregation.', + example: '42', + flat_name: '_doc_count', + name: '_doc_count', + short: + 'A custom field used for storing doc counts when a document represents pre-aggregated data.', + documentation_url: + 'https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-doc-count-field.html', + }, + _field_names: { + dashed_name: 'field_names', + description: + 'All fields in the document which contain non-null values. This metadata field lists the field names that have valid data.', + example: '["user", "message"]', + flat_name: '_field_names', + name: '_field_names', + short: 'Fields with non-null values.', + documentation_url: + 'https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-field-names-field.html', + }, + _ignored: { + dashed_name: 'ignored', + description: + 'All fields in the document that have been ignored at index time because of ignore_malformed. It indicates fields that were not indexed due to malformation.', + example: '["malformed_field"]', + flat_name: '_ignored', + name: '_ignored', + short: 'Fields ignored during indexing.', + documentation_url: + 'https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-ignored-field.html', + }, + _routing: { + dashed_name: 'routing', + description: + 'A custom routing value which routes a document to a particular shard. This field is used to control the shard placement of a document.', + example: 'user_routing_value', + flat_name: '_routing', + name: '_routing', + short: 'Custom shard routing value.', + type: 'keyword', + documentation_url: + 'https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-routing-field.html', + }, + _meta: { + dashed_name: 'meta', + description: + 'Application specific metadata. This field can store any custom metadata relevant to the application using Elasticsearch.', + example: '{"app": "my_app"}', + flat_name: '_meta', + name: '_meta', + short: 'Custom application metadata.', + documentation_url: + 'https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-meta-field.html', + }, + _tier: { + dashed_name: 'tier', + description: + 'The current data tier preference of the index to which the document belongs. It helps in managing the index’s storage tier.', + example: 'hot', + flat_name: '_tier', + name: '_tier', + short: 'Index data tier preference.', + documentation_url: + 'https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-tier-field.html', + }, +}; diff --git a/x-pack/plugins/fields_metadata/server/services/fields_metadata/fields_metadata_client.test.ts b/x-pack/plugins/fields_metadata/server/services/fields_metadata/fields_metadata_client.test.ts index 0d35dc70fd678..e693725a93d89 100644 --- a/x-pack/plugins/fields_metadata/server/services/fields_metadata/fields_metadata_client.test.ts +++ b/x-pack/plugins/fields_metadata/server/services/fields_metadata/fields_metadata_client.test.ts @@ -4,11 +4,12 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { FieldMetadata, TEcsFields } from '../../../common'; +import { FieldMetadata, TEcsFields, TMetadataFields } from '../../../common'; import { loggerMock } from '@kbn/logging-mocks'; import { FieldsMetadataClient } from './fields_metadata_client'; import { EcsFieldsRepository } from './repositories/ecs_fields_repository'; import { IntegrationFieldsRepository } from './repositories/integration_fields_repository'; +import { MetadataFieldsRepository } from './repositories/metadata_fields_repository'; const ecsFields = { '@timestamp': { @@ -26,6 +27,21 @@ const ecsFields = { }, } as TEcsFields; +const metadataFields = { + _index: { + dashed_name: 'index', + description: + 'The index to which the document belongs. This metadata field specifies the exact index name in which the document is stored.', + example: 'index_1', + flat_name: '_index', + name: '_index', + short: 'The index to which the document belongs.', + type: 'keyword', + documentation_url: + 'https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-index-field.html', + }, +} as TMetadataFields; + const integrationFields = { '1password.item_usages': { 'onepassword.client.platform_version': { @@ -46,6 +62,7 @@ const integrationFields = { describe('FieldsMetadataClient class', () => { const logger = loggerMock.create(); const ecsFieldsRepository = EcsFieldsRepository.create({ ecsFields }); + const metadataFieldsRepository = MetadataFieldsRepository.create({ metadataFields }); const integrationFieldsExtractor = jest.fn(); integrationFieldsExtractor.mockImplementation(() => Promise.resolve(integrationFields)); @@ -60,12 +77,13 @@ describe('FieldsMetadataClient class', () => { fieldsMetadataClient = FieldsMetadataClient.create({ ecsFieldsRepository, integrationFieldsRepository, + metadataFieldsRepository, logger, }); }); describe('#getByName', () => { - it('should resolve a single ECS FieldMetadata instance by default', async () => { + it('should resolve a single ECS/Metadata FieldMetadata instance by default', async () => { const timestampFieldInstance = await fieldsMetadataClient.getByName('@timestamp'); expect(integrationFieldsExtractor).not.toHaveBeenCalled(); @@ -87,7 +105,7 @@ describe('FieldsMetadataClient class', () => { expect(timestampField.hasOwnProperty('type')).toBeTruthy(); }); - it('should attempt resolving the field from an integration if it does not exist in ECS and the integration and dataset params are provided', async () => { + it('should attempt resolving the field from an integration if it does not exist in ECS/Metadata and the integration and dataset params are provided', async () => { const onePasswordFieldInstance = await fieldsMetadataClient.getByName( 'onepassword.client.platform_version', { integration: '1password', dataset: '1password.item_usages' } diff --git a/x-pack/plugins/fields_metadata/server/services/fields_metadata/fields_metadata_client.ts b/x-pack/plugins/fields_metadata/server/services/fields_metadata/fields_metadata_client.ts index e152c14347927..87c9b6547f4f5 100644 --- a/x-pack/plugins/fields_metadata/server/services/fields_metadata/fields_metadata_client.ts +++ b/x-pack/plugins/fields_metadata/server/services/fields_metadata/fields_metadata_client.ts @@ -9,12 +9,14 @@ import { Logger } from '@kbn/core/server'; import { FieldName, FieldMetadata, FieldsMetadataDictionary } from '../../../common'; import { EcsFieldsRepository } from './repositories/ecs_fields_repository'; import { IntegrationFieldsRepository } from './repositories/integration_fields_repository'; +import { MetadataFieldsRepository } from './repositories/metadata_fields_repository'; import { IntegrationFieldsSearchParams } from './repositories/types'; import { FindFieldsMetadataOptions, IFieldsMetadataClient } from './types'; interface FieldsMetadataClientDeps { logger: Logger; ecsFieldsRepository: EcsFieldsRepository; + metadataFieldsRepository: MetadataFieldsRepository; integrationFieldsRepository: IntegrationFieldsRepository; } @@ -22,6 +24,7 @@ export class FieldsMetadataClient implements IFieldsMetadataClient { private constructor( private readonly logger: Logger, private readonly ecsFieldsRepository: EcsFieldsRepository, + private readonly metadataFieldsRepository: MetadataFieldsRepository, private readonly integrationFieldsRepository: IntegrationFieldsRepository ) {} @@ -31,8 +34,13 @@ export class FieldsMetadataClient implements IFieldsMetadataClient { ): Promise { this.logger.debug(`Retrieving field metadata for: ${fieldName}`); - // 1. Try resolving from ecs static metadata - let field = this.ecsFieldsRepository.getByName(fieldName); + // 1. Try resolving from metadata-fields static metadata + let field = this.metadataFieldsRepository.getByName(fieldName); + + // 2. Try resolving from ecs static metadata + if (!field) { + field = this.ecsFieldsRepository.getByName(fieldName); + } // 2. Try searching for the fiels in the Elastic Package Registry if (!field && integration) { @@ -48,7 +56,10 @@ export class FieldsMetadataClient implements IFieldsMetadataClient { dataset, }: FindFieldsMetadataOptions = {}): Promise { if (!fieldNames) { - return this.ecsFieldsRepository.find(); + return FieldsMetadataDictionary.create({ + ...this.metadataFieldsRepository.find().getFields(), + ...this.ecsFieldsRepository.find().getFields(), + }); } const fields: Record = {}; @@ -66,8 +77,14 @@ export class FieldsMetadataClient implements IFieldsMetadataClient { public static create({ logger, ecsFieldsRepository, + metadataFieldsRepository, integrationFieldsRepository, }: FieldsMetadataClientDeps) { - return new FieldsMetadataClient(logger, ecsFieldsRepository, integrationFieldsRepository); + return new FieldsMetadataClient( + logger, + ecsFieldsRepository, + metadataFieldsRepository, + integrationFieldsRepository + ); } } diff --git a/x-pack/plugins/fields_metadata/server/services/fields_metadata/fields_metadata_service.ts b/x-pack/plugins/fields_metadata/server/services/fields_metadata/fields_metadata_service.ts index 391da465e9a1f..8313f0337d769 100644 --- a/x-pack/plugins/fields_metadata/server/services/fields_metadata/fields_metadata_service.ts +++ b/x-pack/plugins/fields_metadata/server/services/fields_metadata/fields_metadata_service.ts @@ -10,8 +10,10 @@ import { Logger } from '@kbn/core/server'; import { FieldsMetadataClient } from './fields_metadata_client'; import { EcsFieldsRepository } from './repositories/ecs_fields_repository'; import { IntegrationFieldsRepository } from './repositories/integration_fields_repository'; +import { MetadataFieldsRepository } from './repositories/metadata_fields_repository'; import { IntegrationFieldsExtractor } from './repositories/types'; import { FieldsMetadataServiceSetup, FieldsMetadataServiceStart } from './types'; +import { MetadataFields as metadataFields } from '../../../common/metadata_fields'; export class FieldsMetadataService { private integrationFieldsExtractor: IntegrationFieldsExtractor = () => Promise.resolve({}); @@ -30,6 +32,7 @@ export class FieldsMetadataService { const { logger, integrationFieldsExtractor } = this; const ecsFieldsRepository = EcsFieldsRepository.create({ ecsFields }); + const metadataFieldsRepository = MetadataFieldsRepository.create({ metadataFields }); const integrationFieldsRepository = IntegrationFieldsRepository.create({ integrationFieldsExtractor, }); @@ -39,6 +42,7 @@ export class FieldsMetadataService { return FieldsMetadataClient.create({ logger, ecsFieldsRepository, + metadataFieldsRepository, integrationFieldsRepository, }); }, diff --git a/x-pack/plugins/fields_metadata/server/services/fields_metadata/repositories/ecs_fields_repository.ts b/x-pack/plugins/fields_metadata/server/services/fields_metadata/repositories/ecs_fields_repository.ts index 05f34bbf0ee60..d8fb947bdd6c5 100644 --- a/x-pack/plugins/fields_metadata/server/services/fields_metadata/repositories/ecs_fields_repository.ts +++ b/x-pack/plugins/fields_metadata/server/services/fields_metadata/repositories/ecs_fields_repository.ts @@ -7,18 +7,18 @@ import mapValues from 'lodash/mapValues'; import { FieldsMetadataDictionary } from '../../../../common/fields_metadata/models/fields_metadata_dictionary'; -import { FieldMetadata, FieldName, TEcsFields } from '../../../../common'; +import { AnyFieldName, EcsFieldName, FieldMetadata, TEcsFields } from '../../../../common'; interface EcsFieldsRepositoryDeps { ecsFields: TEcsFields; } interface FindOptions { - fieldNames?: FieldName[]; + fieldNames?: EcsFieldName[]; } export class EcsFieldsRepository { - private readonly ecsFields: Record; + private readonly ecsFields: Record; private constructor(ecsFields: TEcsFields) { this.ecsFields = mapValues(ecsFields, (field) => @@ -26,8 +26,8 @@ export class EcsFieldsRepository { ); } - getByName(fieldName: FieldName): FieldMetadata | undefined { - return this.ecsFields[fieldName]; + getByName(fieldName: EcsFieldName | AnyFieldName): FieldMetadata | undefined { + return this.ecsFields[fieldName as EcsFieldName]; } find({ fieldNames }: FindOptions = {}): FieldsMetadataDictionary { @@ -43,7 +43,7 @@ export class EcsFieldsRepository { } return fieldsMetadata; - }, {} as Record); + }, {} as Record); return FieldsMetadataDictionary.create(fields); } diff --git a/x-pack/plugins/fields_metadata/server/services/fields_metadata/repositories/metadata_fields_repository.ts b/x-pack/plugins/fields_metadata/server/services/fields_metadata/repositories/metadata_fields_repository.ts new file mode 100644 index 0000000000000..1276c672acb62 --- /dev/null +++ b/x-pack/plugins/fields_metadata/server/services/fields_metadata/repositories/metadata_fields_repository.ts @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import mapValues from 'lodash/mapValues'; +import { MetadataFieldName } from '../../../../common/fields_metadata'; +import { FieldsMetadataDictionary } from '../../../../common/fields_metadata/models/fields_metadata_dictionary'; +import { AnyFieldName, FieldMetadata, TMetadataFields } from '../../../../common'; + +interface MetadataFieldsRepositoryDeps { + metadataFields: TMetadataFields; +} + +interface FindOptions { + fieldNames?: MetadataFieldName[]; +} + +export class MetadataFieldsRepository { + private readonly metadataFields: Record; + + private constructor(metadataFields: TMetadataFields) { + this.metadataFields = mapValues(metadataFields, (field) => + FieldMetadata.create({ ...field, source: 'metadata' }) + ); + } + + getByName(fieldName: MetadataFieldName | AnyFieldName): FieldMetadata | undefined { + return this.metadataFields[fieldName as MetadataFieldName]; + } + + find({ fieldNames }: FindOptions = {}): FieldsMetadataDictionary { + if (!fieldNames) { + return FieldsMetadataDictionary.create(this.metadataFields); + } + + const fields = fieldNames.reduce((fieldsMetadata, fieldName) => { + const field = this.getByName(fieldName); + + if (field) { + fieldsMetadata[fieldName] = field; + } + + return fieldsMetadata; + }, {} as Record); + + return FieldsMetadataDictionary.create(fields); + } + + public static create({ metadataFields }: MetadataFieldsRepositoryDeps) { + return new MetadataFieldsRepository(metadataFields); + } +} diff --git a/x-pack/plugins/fleet/common/services/agent_policies_helper.test.ts b/x-pack/plugins/fleet/common/services/agent_policies_helper.test.ts index ded9ae843ad64..2ddac31675e35 100644 --- a/x-pack/plugins/fleet/common/services/agent_policies_helper.test.ts +++ b/x-pack/plugins/fleet/common/services/agent_policies_helper.test.ts @@ -61,4 +61,8 @@ describe('getInheritedNamespace', () => { it('should return default namespace when there are no agent policies', () => { expect(getInheritedNamespace([])).toEqual('default'); }); + + it('should allow to override default namespace when there are no agent policies', () => { + expect(getInheritedNamespace([], 'test')).toEqual('test'); + }); }); diff --git a/x-pack/plugins/fleet/common/services/agent_policies_helpers.ts b/x-pack/plugins/fleet/common/services/agent_policies_helpers.ts index 7260e389e14fb..8a1e268614684 100644 --- a/x-pack/plugins/fleet/common/services/agent_policies_helpers.ts +++ b/x-pack/plugins/fleet/common/services/agent_policies_helpers.ts @@ -45,9 +45,9 @@ function policyHasIntegration(agentPolicy: AgentPolicy, packageName: string) { return agentPolicy.package_policies?.some((p) => p.package?.name === packageName); } -export function getInheritedNamespace(agentPolicies: AgentPolicy[]): string { +export function getInheritedNamespace(agentPolicies: AgentPolicy[], defaultValue?: string): string { if (agentPolicies.length === 1) { return agentPolicies[0].namespace; } - return 'default'; + return defaultValue ?? 'default'; } diff --git a/x-pack/plugins/fleet/common/services/is_valid_namespace.test.ts b/x-pack/plugins/fleet/common/services/is_valid_namespace.test.ts index ebd6b98a732b9..f35fb4af2f142 100644 --- a/x-pack/plugins/fleet/common/services/is_valid_namespace.test.ts +++ b/x-pack/plugins/fleet/common/services/is_valid_namespace.test.ts @@ -14,6 +14,10 @@ describe('Fleet - isValidNamespace', () => { expect(isValidNamespace('testlength😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀').valid).toBe( true ); + expect(isValidNamespace('', true).valid).toBe(true); + expect(isValidNamespace('', true, ['test']).valid).toBe(true); + expect(isValidNamespace('test', false, ['test']).valid).toBe(true); + expect(isValidNamespace('test_dev', false, ['test']).valid).toBe(true); }); it('returns false for invalid namespaces', () => { @@ -36,5 +40,6 @@ describe('Fleet - isValidNamespace', () => { 'testlength😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀😀' ).valid ).toBe(false); + expect(isValidNamespace('default', false, ['test']).valid).toBe(false); }); }); diff --git a/x-pack/plugins/fleet/common/services/is_valid_namespace.ts b/x-pack/plugins/fleet/common/services/is_valid_namespace.ts index dcc1a2b9b5cbf..bb7d6bb2f49c5 100644 --- a/x-pack/plugins/fleet/common/services/is_valid_namespace.ts +++ b/x-pack/plugins/fleet/common/services/is_valid_namespace.ts @@ -12,9 +12,43 @@ import { i18n } from '@kbn/i18n'; // and implements a limit based on https://github.com/elastic/kibana/issues/75846 export function isValidNamespace( namespace: string, - allowBlankNamespace?: boolean + allowBlankNamespace?: boolean, + allowedNamespacePrefixes?: string[] ): { valid: boolean; error?: string } { - return isValidEntity(namespace, 'Namespace', allowBlankNamespace); + if (!namespace.trim() && allowBlankNamespace) { + return { valid: true }; + } + + const { valid, error } = isValidEntity(namespace, 'Namespace', allowBlankNamespace); + if (!valid) { + return { valid, error }; + } + + for (const prefix of allowedNamespacePrefixes || []) { + if (!namespace.trim().startsWith(prefix)) { + return allowedNamespacePrefixes?.length === 1 + ? { + valid: false, + error: i18n.translate('xpack.fleet.namespaceValidation.notAllowedPrefixError', { + defaultMessage: 'Namespace should start with {allowedNamespacePrefixes}', + values: { + allowedNamespacePrefixes: allowedNamespacePrefixes?.[0], + }, + }), + } + : { + valid: false, + error: i18n.translate('xpack.fleet.namespaceValidation.notAllowedPrefixesError', { + defaultMessage: + 'Namespace should start with one of these prefixes {allowedNamespacePrefixes}', + values: { + allowedNamespacePrefixes: allowedNamespacePrefixes?.join(', ') ?? '', + }, + }), + }; + } + } + return { valid: true }; } export function isValidDataset( diff --git a/x-pack/plugins/fleet/common/services/routes.ts b/x-pack/plugins/fleet/common/services/routes.ts index decef8fe628d5..1b8551d89b832 100644 --- a/x-pack/plugins/fleet/common/services/routes.ts +++ b/x-pack/plugins/fleet/common/services/routes.ts @@ -287,6 +287,7 @@ export const settingsRoutesService = { getInfoPath: () => SETTINGS_API_ROUTES.INFO_PATTERN, getUpdatePath: () => SETTINGS_API_ROUTES.UPDATE_PATTERN, getEnrollmentInfoPath: () => SETTINGS_API_ROUTES.ENROLLMENT_INFO_PATTERN, + getSpaceInfoPath: () => SETTINGS_API_ROUTES.SPACE_INFO_PATTERN, }; export const appRoutesService = { diff --git a/x-pack/plugins/fleet/common/services/validate_package_policy.ts b/x-pack/plugins/fleet/common/services/validate_package_policy.ts index 1de38822cbc80..69a26e6747771 100644 --- a/x-pack/plugins/fleet/common/services/validate_package_policy.ts +++ b/x-pack/plugins/fleet/common/services/validate_package_policy.ts @@ -56,7 +56,8 @@ export type PackagePolicyValidationResults = { export const validatePackagePolicy = ( packagePolicy: NewPackagePolicy, packageInfo: PackageInfo, - safeLoadYaml: (yaml: string) => any + safeLoadYaml: (yaml: string) => any, + spaceSettings?: { allowedNamespacePrefixes?: string[] } ): PackagePolicyValidationResults => { const hasIntegrations = doesPackageHaveIntegrations(packageInfo); const validationResults: PackagePolicyValidationResults = { @@ -75,7 +76,11 @@ export const validatePackagePolicy = ( } if (packagePolicy?.namespace) { - const namespaceValidation = isValidNamespace(packagePolicy?.namespace, true); + const namespaceValidation = isValidNamespace( + packagePolicy?.namespace, + true, + spaceSettings?.allowedNamespacePrefixes + ); if (!namespaceValidation.valid && namespaceValidation.error) { validationResults.namespace = [namespaceValidation.error]; } diff --git a/x-pack/plugins/fleet/common/types/index.ts b/x-pack/plugins/fleet/common/types/index.ts index 4ec0647480165..d5582bc87e37a 100644 --- a/x-pack/plugins/fleet/common/types/index.ts +++ b/x-pack/plugins/fleet/common/types/index.ts @@ -33,6 +33,11 @@ export interface FleetConfigType { agentless?: { api: { url: string; + tls: { + certificate: string; + key: string; + ca: string; + }; }; }; spaceSettings?: Array<{ diff --git a/x-pack/plugins/fleet/common/types/models/agent_policy.ts b/x-pack/plugins/fleet/common/types/models/agent_policy.ts index 082296fd75e11..bc70714b79158 100644 --- a/x-pack/plugins/fleet/common/types/models/agent_policy.ts +++ b/x-pack/plugins/fleet/common/types/models/agent_policy.ts @@ -212,3 +212,8 @@ export interface FleetServerPolicy { */ inactivity_timeout?: number; } + +export interface AgentlessApiResponse { + id: string; + region_id: string; +} diff --git a/x-pack/plugins/fleet/dev_docs/local_setup/developing_kibana_and_fleet_server.md b/x-pack/plugins/fleet/dev_docs/local_setup/developing_kibana_and_fleet_server.md index 9752e129e1d40..daf1d152f3bb1 100644 --- a/x-pack/plugins/fleet/dev_docs/local_setup/developing_kibana_and_fleet_server.md +++ b/x-pack/plugins/fleet/dev_docs/local_setup/developing_kibana_and_fleet_server.md @@ -149,7 +149,7 @@ $ DEV=true SNAPSHOT=true make release-darwin/amd64 # Run dev build, provide your fingerprint and service token from before # Replace 8.13.0-SNAPSHOT with the latest version on main -$ ./build/binaries/fleet-server-8.13.0-SNAPSHOT-darwin-x86_64/fleet-server -c fleet-server.dev.yml +$ ./build/binaries/fleet-server-8.13.0-SNAPSHOT-darwin-aarch64/fleet-server -c fleet-server.dev.yml ``` Now you should have a local ES snapshot running on http://localhost:9200, a local Kibana running on http://localhost:5601, and a local Fleet Server running on http://localhost:8220. You can now navigate to http://localhost:5601/app/fleet and [enroll agents](#enroll-agents). diff --git a/x-pack/plugins/fleet/public/applications/fleet/app.tsx b/x-pack/plugins/fleet/public/applications/fleet/app.tsx index 5d3dee34339cc..65a57cc81523b 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/app.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/app.tsx @@ -26,6 +26,7 @@ import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common'; import type { FleetConfigType, FleetStartServices } from '../../plugin'; import { PackageInstallProvider } from '../integrations/hooks'; +import { SpaceSettingsContextProvider } from '../../hooks/use_space_settings_context'; import { type FleetStatusProviderProps, useAuthz, useFleetStatus, useFlyoutContext } from './hooks'; @@ -213,11 +214,13 @@ export const FleetAppContext: React.FC<{ - - - {children} - - + + + + {children} + + + diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.test.ts b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.test.ts index 1fc2a673c0d32..21a2cc53257f7 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.test.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.test.ts @@ -35,9 +35,9 @@ describe('getInstallCommandForPlatform', () => { ); expect(res).toMatchInlineSnapshot(` - "curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--darwin-x86_64.tar.gz - tar xzvf elastic-agent--darwin-x86_64.tar.gz - cd elastic-agent--darwin-x86_64 + "curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--darwin-aarch64.tar.gz + tar xzvf elastic-agent--darwin-aarch64.tar.gz + cd elastic-agent--darwin-aarch64 sudo ./elastic-agent install \\\\ --fleet-server-es=http://elasticsearch:9200 \\\\ --fleet-server-service-token=service-token-1 \\\\ @@ -156,9 +156,9 @@ describe('getInstallCommandForPlatform', () => { ); expect(res).toMatchInlineSnapshot(` - "curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--darwin-x86_64.tar.gz - tar xzvf elastic-agent--darwin-x86_64.tar.gz - cd elastic-agent--darwin-x86_64 + "curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--darwin-aarch64.tar.gz + tar xzvf elastic-agent--darwin-aarch64.tar.gz + cd elastic-agent--darwin-aarch64 sudo ./elastic-agent install \\\\ --fleet-server-es=http://elasticsearch:9200 \\\\ --fleet-server-service-token=service-token-1 \\\\ @@ -301,9 +301,9 @@ describe('getInstallCommandForPlatform', () => { ); expect(res).toMatchInlineSnapshot(` - "curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--darwin-x86_64.tar.gz - tar xzvf elastic-agent--darwin-x86_64.tar.gz - cd elastic-agent--darwin-x86_64 + "curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--darwin-aarch64.tar.gz + tar xzvf elastic-agent--darwin-aarch64.tar.gz + cd elastic-agent--darwin-aarch64 sudo ./elastic-agent install --url=http://fleetserver:8220 \\\\ --fleet-server-es=http://elasticsearch:9200 \\\\ --fleet-server-service-token=service-token-1 \\\\ diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.ts b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.ts index 2438cf4e53a2f..79809b94470e4 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.ts @@ -35,9 +35,9 @@ function getArtifact( }, mac: { downloadCommand: [ - `curl -L -O ${ARTIFACT_BASE_URL}/elastic-agent-${kibanaVersion}-darwin-x86_64.tar.gz`, - `tar xzvf elastic-agent-${kibanaVersion}-darwin-x86_64.tar.gz`, - `cd elastic-agent-${kibanaVersion}-darwin-x86_64`, + `curl -L -O ${ARTIFACT_BASE_URL}/elastic-agent-${kibanaVersion}-darwin-aarch64.tar.gz`, + `tar xzvf elastic-agent-${kibanaVersion}-darwin-aarch64.tar.gz`, + `cd elastic-agent-${kibanaVersion}-darwin-aarch64`, ].join(`\n`), }, windows: { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx index ef5dc9b8e3c4d..c17e3345bfd1d 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx @@ -63,6 +63,7 @@ import { CustomFields } from './custom_fields'; interface Props { agentPolicy: Partial; + allowedNamespacePrefixes?: string[]; updateAgentPolicy: (u: Partial) => void; validation: ValidationResults; disabled?: boolean; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_create_inline.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_create_inline.tsx index 4ca70267c7ed1..96e1056f736cd 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_create_inline.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_create_inline.tsx @@ -22,14 +22,12 @@ import { FormattedMessage } from '@kbn/i18n-react'; import styled from 'styled-components'; import { i18n } from '@kbn/i18n'; +import { useSpaceSettingsContext } from '../../../../../hooks/use_space_settings_context'; import type { AgentPolicy, NewAgentPolicy } from '../../../types'; - import { sendCreateAgentPolicy, useStartServices, useAuthz } from '../../../hooks'; - import { generateNewAgentPolicyWithDefaults } from '../../../../../../common/services/generate_new_agent_policy'; import { agentPolicyFormValidation } from '.'; - import { AgentPolicyAdvancedOptionsContent } from './agent_policy_advanced_fields'; import { AgentPolicyFormSystemMonitoringCheckbox } from './agent_policy_system_monitoring_field'; @@ -58,11 +56,13 @@ export const AgentPolicyCreateInlineForm: React.FunctionComponent = ({ const [isLoading, setIsLoading] = useState(false); const isDisabled = !authz.fleet.allAgentPolicies || isLoading; + const spaceSettings = useSpaceSettingsContext(); const [newAgentPolicy, setNewAgentPolicy] = useState( generateNewAgentPolicyWithDefaults({ name: agentPolicyName, has_fleet_server: isFleetServerPolicy, + namespace: spaceSettings.defaultNamespace, }) ); @@ -76,7 +76,9 @@ export const AgentPolicyCreateInlineForm: React.FunctionComponent = ({ [setNewAgentPolicy, newAgentPolicy] ); - const validation = agentPolicyFormValidation(newAgentPolicy); + const validation = agentPolicyFormValidation(newAgentPolicy, { + allowedNamespacePrefixes: spaceSettings.allowedNamespacePrefixes, + }); const createAgentPolicy = useCallback(async () => { try { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_validation.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_validation.tsx index 4ba769c311523..bb4e39b265f06 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_validation.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_validation.tsx @@ -15,10 +15,15 @@ export interface ValidationResults { } export const agentPolicyFormValidation = ( - agentPolicy: Partial + agentPolicy: Partial, + options?: { allowedNamespacePrefixes?: string[] } ): ValidationResults => { const errors: ValidationResults = {}; - const namespaceValidation = isValidNamespace(agentPolicy.namespace || ''); + const namespaceValidation = isValidNamespace( + agentPolicy.namespace || '', + false, + options?.allowedNamespacePrefixes + ); if (!agentPolicy.name?.trim()) { errors.name = [ diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/form.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/form.tsx index 02e364f3e3d30..4f8d616b2ff6c 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/form.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/form.tsx @@ -11,6 +11,7 @@ import { safeLoad } from 'js-yaml'; import { isEqual } from 'lodash'; +import { useSpaceSettingsContext } from '../../../../../../../hooks/use_space_settings_context'; import type { AgentPolicy, NewPackagePolicy, @@ -152,6 +153,7 @@ export function useOnSubmit({ }) { const { notifications } = useStartServices(); const confirmForceInstall = useConfirmForceInstall(); + const spaceSettings = useSpaceSettingsContext(); // only used to store the resulting package policy once saved const [savedPackagePolicy, setSavedPackagePolicy] = useState(); // Form state @@ -204,7 +206,8 @@ export function useOnSubmit({ const newValidationResult = validatePackagePolicy( newPackagePolicy || packagePolicy, packageInfo, - safeLoad + safeLoad, + spaceSettings ); setValidationResults(newValidationResult); // eslint-disable-next-line no-console @@ -213,7 +216,7 @@ export function useOnSubmit({ return newValidationResult; } }, - [packagePolicy, packageInfo] + [packagePolicy, packageInfo, spaceSettings] ); // Update package policy method const updatePackagePolicy = useCallback( diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx index 886761404563f..67275a3cf4036 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx @@ -25,6 +25,7 @@ import { } from '@elastic/eui'; import type { EuiStepProps } from '@elastic/eui/src/components/steps/step'; +import { useSpaceSettingsContext } from '../../../../../../hooks/use_space_settings_context'; import { SECRETS_MINIMUM_FLEET_SERVER_VERSION } from '../../../../../../../common/constants'; import { @@ -111,12 +112,18 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({ const { params } = useRouteMatch(); const fleetStatus = useFleetStatus(); const { docLinks } = useStartServices(); + const spaceSettings = useSpaceSettingsContext(); const [newAgentPolicy, setNewAgentPolicy] = useState( - generateNewAgentPolicyWithDefaults({ name: 'Agent policy 1' }) + generateNewAgentPolicyWithDefaults({ + name: 'Agent policy 1', + namespace: spaceSettings.defaultNamespace, + }) ); const [withSysMonitoring, setWithSysMonitoring] = useState(true); - const validation = agentPolicyFormValidation(newAgentPolicy); + const validation = agentPolicyFormValidation(newAgentPolicy, { + allowedNamespacePrefixes: spaceSettings.allowedNamespacePrefixes, + }); const [selectedPolicyTab, setSelectedPolicyTab] = useState( queryParamsPolicyId ? SelectedPolicyTab.EXISTING : SelectedPolicyTab.NEW @@ -379,7 +386,10 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({ ) : packageInfo ? ( <> ( const [agentPolicy, setAgentPolicy] = useState({ ...originalAgentPolicy, }); + const spaceSettings = useSpaceSettingsContext(); + const [isLoading, setIsLoading] = useState(false); const [hasChanges, setHasChanges] = useState(false); const [agentCount, setAgentCount] = useState(0); const [withSysMonitoring, setWithSysMonitoring] = useState(true); - const validation = agentPolicyFormValidation(agentPolicy); + const validation = agentPolicyFormValidation(agentPolicy, { + allowedNamespacePrefixes: spaceSettings?.allowedNamespacePrefixes, + }); const [hasAdvancedSettingsErrors, setHasAdvancedSettingsErrors] = useState(false); const updateAgentPolicy = (updatedFields: Partial) => { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/hooks/use_package_policy_steps.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/hooks/use_package_policy_steps.tsx index 9ce4d8b81157e..9ade778c74f31 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/hooks/use_package_policy_steps.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/hooks/use_package_policy_steps.tsx @@ -10,6 +10,7 @@ import { isEqual } from 'lodash'; import { i18n } from '@kbn/i18n'; import type { EuiStepProps } from '@elastic/eui'; +import { useSpaceSettingsContext } from '../../../../../../hooks/use_space_settings_context'; import type { AgentPolicy, NewAgentPolicy, NewPackagePolicy } from '../../../../../../../common'; import { generateNewAgentPolicyWithDefaults } from '../../../../../../../common/services'; import { SelectedPolicyTab, StepSelectHosts } from '../../create_package_policy_page/components'; @@ -49,8 +50,12 @@ export function usePackagePolicySteps({ packagePolicyId, setNewAgentPolicyName, }: Params) { + const spaceSettings = useSpaceSettingsContext(); const [newAgentPolicy, setNewAgentPolicy] = useState( - generateNewAgentPolicyWithDefaults({ name: 'Agent policy 1' }) + generateNewAgentPolicyWithDefaults({ + name: 'Agent policy 1', + namespace: spaceSettings.defaultNamespace, + }) ); const [withSysMonitoring, setWithSysMonitoring] = useState(true); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/list_page/components/create_agent_policy.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/list_page/components/create_agent_policy.tsx index 39b30b601714e..f147f7e112ea1 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/list_page/components/create_agent_policy.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/list_page/components/create_agent_policy.tsx @@ -24,6 +24,7 @@ import { EuiSpacer, } from '@elastic/eui'; +import { useSpaceSettingsContext } from '../../../../../../hooks/use_space_settings_context'; import type { NewAgentPolicy, AgentPolicy } from '../../../../types'; import { MAX_FLYOUT_WIDTH } from '../../../../constants'; import { useAuthz, useStartServices, sendCreateAgentPolicy } from '../../../../hooks'; @@ -48,12 +49,17 @@ export const CreateAgentPolicyFlyout: React.FunctionComponent = ({ }) => { const { notifications } = useStartServices(); const hasFleetAllAgentPoliciesPrivileges = useAuthz().fleet.allAgentPolicies; + const spaceSettings = useSpaceSettingsContext(); const [agentPolicy, setAgentPolicy] = useState( - generateNewAgentPolicyWithDefaults() + generateNewAgentPolicyWithDefaults({ + namespace: spaceSettings.defaultNamespace, + }) ); const [isLoading, setIsLoading] = useState(false); const [withSysMonitoring, setWithSysMonitoring] = useState(true); - const validation = agentPolicyFormValidation(agentPolicy); + const validation = agentPolicyFormValidation(agentPolicy, { + allowedNamespacePrefixes: spaceSettings?.allowedNamespacePrefixes, + }); const [hasAdvancedSettingsErrors, setHasAdvancedSettingsErrors] = useState(false); const updateAgentPolicy = (updatedFields: Partial) => { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/action_menu.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/action_menu.test.tsx index 5927bb4140e42..fc697c33af044 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/action_menu.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/action_menu.test.tsx @@ -51,6 +51,7 @@ describe('AgentDetailsActionMenu', () => { readAgents: true, allAgents: true, }, + integrations: {}, } as any); mockedUseAgentVersion.mockReturnValue('8.10.2'); }); @@ -133,6 +134,7 @@ describe('AgentDetailsActionMenu', () => { fleet: { readAgents: false, }, + integrations: {}, } as any); const res = renderAndGetDiagnosticsButton({ agent: { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.test.tsx index b13135516d186..10848d3a13c48 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/table_row_actions.test.tsx @@ -61,6 +61,7 @@ describe('TableRowActions', () => { readAgents: true, allAgents: true, }, + integrations: {}, } as any); mockedUseAgentVersion.mockReturnValue('8.10.2'); }); @@ -97,6 +98,7 @@ describe('TableRowActions', () => { fleet: { allAgents: false, }, + integrations: {}, } as any); const res = renderAndGetDiagnosticsButton({ agent: { @@ -192,6 +194,7 @@ describe('TableRowActions', () => { fleet: { readAgents: false, }, + integrations: {}, } as any); const res = renderAndGetRestartUpgradeButton({ agent: { 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 4fcfd807f03c8..95041d7c089d1 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 @@ -41,6 +41,7 @@ export function useFetchAgentsData() { const history = useHistory(); const { urlParams, toUrlParams } = useUrlParams(); const defaultKuery: string = (urlParams.kuery as string) || ''; + const urlHasInactive = (urlParams.showInactive as string) === 'true'; // Agent data states const [showUpgradeable, setShowUpgradeable] = useState(false); @@ -64,12 +65,17 @@ export function useFetchAgentsData() { 'unhealthy', 'updating', 'offline', + ...(urlHasInactive ? ['inactive'] : []), ]); const [selectedTags, setSelectedTags] = useState([]); const showInactive = useMemo(() => { - return selectedStatus.some((status) => status === 'inactive' || status === 'unenrolled'); + return selectedStatus.some((status) => status === 'inactive') || selectedStatus.length === 0; + }, [selectedStatus]); + + const includeUnenrolled = useMemo(() => { + return selectedStatus.some((status) => status === 'unenrolled') || selectedStatus.length === 0; }, [selectedStatus]); const setSearch = useCallback( @@ -89,7 +95,7 @@ export function useFetchAgentsData() { ); // filters kuery - const kuery = useMemo(() => { + let kuery = useMemo(() => { return getKuery({ search, selectedAgentPolicies, @@ -98,6 +104,9 @@ export function useFetchAgentsData() { }); }, [search, selectedAgentPolicies, selectedStatus, selectedTags]); + kuery = + includeUnenrolled && kuery ? `status:* AND (${kuery})` : includeUnenrolled ? `status:*` : kuery; + const [agentsOnCurrentPage, setAgentsOnCurrentPage] = useState([]); const [agentsStatus, setAgentsStatus] = useState< { [key in SimplifiedAgentStatus]: number } | undefined diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/index.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/index.test.tsx index f85e7d4a87510..7720361b33468 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/index.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/index.test.tsx @@ -12,6 +12,7 @@ import { useFleetStatus } from '../../../../hooks/use_fleet_status'; import { useAuthz } from '../../../../hooks/use_authz'; import { AgentsApp } from '.'; +import { useGetSpaceSettings } from '../../hooks'; jest.mock('../../../../hooks/use_fleet_status', () => ({ ...jest.requireActual('../../../../hooks/use_fleet_status'), @@ -49,7 +50,9 @@ describe('AgentApp', () => { readAgents: true, allAgents: true, }, + integrations: {}, } as any); + jest.mocked(useGetSpaceSettings).mockReturnValue({} as any); }); it('should render the loading component if the status is loading', async () => { diff --git a/x-pack/plugins/fleet/public/applications/integrations/app.tsx b/x-pack/plugins/fleet/public/applications/integrations/app.tsx index 21e2ba249b694..992ecff3e49a3 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/app.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/app.tsx @@ -28,6 +28,7 @@ import { KibanaVersionContext, useFleetStatus, } from '../../hooks'; +import { SpaceSettingsContextProvider } from '../../hooks/use_space_settings_context'; import { FleetServerFlyout } from '../fleet/components'; @@ -104,24 +105,26 @@ export const IntegrationsAppContext: React.FC<{ - - - - - - - - - {children} - - - - - - - + + + + + + + + + + {children} + + + + + + + + diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/overview/avc_banner/avc_banner_background.svg b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/overview/avc_banner/avc_banner_background.svg deleted file mode 100644 index cd37f26c95f7b..0000000000000 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/overview/avc_banner/avc_banner_background.svg +++ /dev/null @@ -1,329 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/overview/avc_banner/avc_results_banner_2024.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/overview/avc_banner/avc_results_banner_2024.tsx deleted file mode 100644 index 63a3f68254c6c..0000000000000 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/overview/avc_banner/avc_results_banner_2024.tsx +++ /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 React from 'react'; -import { css } from '@emotion/css'; -import { i18n } from '@kbn/i18n'; -import { EuiButton, EuiCallOut, EuiSpacer, useEuiTheme } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { useKibana } from '@kbn/kibana-react-plugin/public'; - -import avcBannerBackground from './avc_banner_background.svg'; - -export const AVCResultsBanner2024: React.FC<{ onDismiss: () => void }> = ({ onDismiss }) => { - const { docLinks } = useKibana().services; - const { euiTheme } = useEuiTheme(); - const bannerTitle = i18n.translate( - 'xpack.fleet.integrations.epm.elasticDefend.avcResultsBanner.title', - { - defaultMessage: '100% protection with zero false positives.', - } - ); - - const calloutStyles = css({ - paddingLeft: `${euiTheme.size.xl}`, - backgroundImage: `url(${avcBannerBackground})`, - backgroundRepeat: 'no-repeat', - backgroundPositionX: 'right', - backgroundPositionY: 'bottom', - }); - - return ( - - - - - - - - ); -}; diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/overview/overview.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/overview/overview.tsx index f9c2d80d3336e..2859b0ff7d8ae 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/overview/overview.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/overview/overview.tsx @@ -22,6 +22,8 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { AVCResultsBanner2024 } from '@kbn/avc-banner'; + import { isIntegrationPolicyTemplate, isPackagePrerelease, @@ -40,8 +42,6 @@ import { SideBarColumn } from '../../../components/side_bar_column'; import type { FleetStartServices } from '../../../../../../../plugin'; -import { AVCResultsBanner2024 } from './avc_banner/avc_results_banner_2024'; - import { Screenshots } from './screenshots'; import { Readme } from './readme'; import { Details } from './details'; diff --git a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/agent_enrollment_flyout.test.mocks.tsx b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/agent_enrollment_flyout.test.mocks.tsx index 0cdf9f2eed9ce..6658eb5a8e0be 100644 --- a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/agent_enrollment_flyout.test.mocks.tsx +++ b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/agent_enrollment_flyout.test.mocks.tsx @@ -21,6 +21,7 @@ jest.mock('../../hooks', () => { addAgents: true, addFleetServers: true, }, + integrations: {}, }), useFleetStatus: jest.fn().mockReturnValue({ isReady: true }), }; @@ -41,6 +42,7 @@ jest.mock('../../hooks/use_request', () => { sendGetOneAgentPolicy: jest.fn().mockResolvedValue({ data: { item: { package_policies: [] } }, }), + useGetSpaceSettings: jest.fn().mockReturnValue({}), useGetAgentPolicies: jest.fn(), useGetEnrollmentSettings: jest.fn().mockReturnValue({ isLoading: false, diff --git a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/agent_enrollment_flyout.test.tsx b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/agent_enrollment_flyout.test.tsx index f8f1854911505..19709c55665fc 100644 --- a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/agent_enrollment_flyout.test.tsx +++ b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/agent_enrollment_flyout.test.tsx @@ -22,8 +22,6 @@ import { useFleetServerUnhealthy } from '../../applications/fleet/sections/agent import type { FlyOutProps } from './types'; import { AgentEnrollmentFlyout } from '.'; -jest.mock('../../hooks/use_authz'); - const render = (props?: Partial) => { cleanup(); const renderer = createFleetTestRendererMock(); @@ -53,6 +51,7 @@ describe('', () => { fleet: { readAgentPolicies: true, }, + integrations: {}, } as any); jest.mocked(useFleetServerStandalone).mockReturnValue({ isFleetServerStandalone: false }); diff --git a/x-pack/plugins/fleet/public/components/enrollment_instructions/manual/index.tsx b/x-pack/plugins/fleet/public/components/enrollment_instructions/manual/index.tsx index 48490f5454957..e5733983dd754 100644 --- a/x-pack/plugins/fleet/public/components/enrollment_instructions/manual/index.tsx +++ b/x-pack/plugins/fleet/public/components/enrollment_instructions/manual/index.tsx @@ -59,9 +59,9 @@ tar xzvf elastic-agent-${agentVersion}-linux-x86_64.tar.gz cd elastic-agent-${agentVersion}-linux-x86_64 sudo ./elastic-agent install ${enrollArgs}`; - const macCommand = `curl -L -O ${downloadBaseUrl}/beats/elastic-agent/elastic-agent-${agentVersion}-darwin-x86_64.tar.gz -tar xzvf elastic-agent-${agentVersion}-darwin-x86_64.tar.gz -cd elastic-agent-${agentVersion}-darwin-x86_64 + const macCommand = `curl -L -O ${downloadBaseUrl}/beats/elastic-agent/elastic-agent-${agentVersion}-darwin-aarch64.tar.gz +tar xzvf elastic-agent-${agentVersion}-darwin-aarch64.tar.gz +cd elastic-agent-${agentVersion}-darwin-aarch64 sudo ./elastic-agent install ${enrollArgs}`; const windowsCommand = `$ProgressPreference = 'SilentlyContinue' diff --git a/x-pack/plugins/fleet/public/components/enrollment_instructions/standalone/index.tsx b/x-pack/plugins/fleet/public/components/enrollment_instructions/standalone/index.tsx index 54a03d9dc942c..21221fdaba79f 100644 --- a/x-pack/plugins/fleet/public/components/enrollment_instructions/standalone/index.tsx +++ b/x-pack/plugins/fleet/public/components/enrollment_instructions/standalone/index.tsx @@ -18,9 +18,9 @@ tar xzvf elastic-agent-${agentVersion}-linux-x86_64.tar.gz cd elastic-agent-${agentVersion}-linux-x86_64 sudo ./elastic-agent install`; - const macCommand = `curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent-${agentVersion}-darwin-x86_64.tar.gz -tar xzvf elastic-agent-${agentVersion}-darwin-x86_64.tar.gz -cd elastic-agent-${agentVersion}-darwin-x86_64 + const macCommand = `curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent-${agentVersion}-darwin-aarch64.tar.gz +tar xzvf elastic-agent-${agentVersion}-darwin-aarch64.tar.gz +cd elastic-agent-${agentVersion}-darwin-aarch64 sudo ./elastic-agent install`; const windowsCommand = `$ProgressPreference = 'SilentlyContinue' diff --git a/x-pack/plugins/fleet/public/components/linked_agent_count.tsx b/x-pack/plugins/fleet/public/components/linked_agent_count.tsx index 1007c5ab54db8..5b92ac3e96f6e 100644 --- a/x-pack/plugins/fleet/public/components/linked_agent_count.tsx +++ b/x-pack/plugins/fleet/public/components/linked_agent_count.tsx @@ -43,7 +43,7 @@ export const LinkedAgentCount = memo< }`; return count > 0 ? ( - + {displayValue} ) : ( diff --git a/x-pack/plugins/fleet/public/constants/page_paths.ts b/x-pack/plugins/fleet/public/constants/page_paths.ts index f3a0fb26de672..1b33c6937c29d 100644 --- a/x-pack/plugins/fleet/public/constants/page_paths.ts +++ b/x-pack/plugins/fleet/public/constants/page_paths.ts @@ -223,7 +223,16 @@ export const pagePathGetters: { FLEET_BASE_PATH, `/policies/${policyId}/upgrade-package-policy/${packagePolicyId}`, ], - agent_list: ({ kuery }) => [FLEET_BASE_PATH, `/agents${kuery ? `?kuery=${kuery}` : ''}`], + agent_list: ({ kuery, showInactive }) => [ + FLEET_BASE_PATH, + `/agents${ + kuery && showInactive + ? `?kuery=${kuery}&showInactive=true` + : showInactive + ? '?showInactive=true' + : '' + }`, + ], agent_details: ({ agentId, tabId, logQuery }) => [ FLEET_BASE_PATH, `/agents/${agentId}${tabId ? `/${tabId}` : ''}${logQuery ? `?_q=${logQuery}` : ''}`, diff --git a/x-pack/plugins/fleet/public/hooks/use_request/settings.ts b/x-pack/plugins/fleet/public/hooks/use_request/settings.ts index 671f7af644716..f9fc3028e1d6b 100644 --- a/x-pack/plugins/fleet/public/hooks/use_request/settings.ts +++ b/x-pack/plugins/fleet/public/hooks/use_request/settings.ts @@ -14,6 +14,7 @@ import type { GetSettingsResponse, GetEnrollmentSettingsRequest, GetEnrollmentSettingsResponse, + GetSpaceSettingsResponse, } from '../../types'; import { API_VERSIONS } from '../../../common/constants'; @@ -42,6 +43,19 @@ export function useGetSettings() { }); } +export function useGetSpaceSettings({ enabled }: { enabled?: boolean }) { + return useQuery({ + queryKey: ['space_settings'], + enabled, + queryFn: () => + sendRequestForRq({ + method: 'get', + path: settingsRoutesService.getSpaceInfoPath(), + version: API_VERSIONS.public.v1, + }), + }); +} + export function sendGetSettings() { return sendRequest({ method: 'get', diff --git a/x-pack/plugins/fleet/public/hooks/use_space_settings_context.test.tsx b/x-pack/plugins/fleet/public/hooks/use_space_settings_context.test.tsx new file mode 100644 index 0000000000000..6f3d286db3706 --- /dev/null +++ b/x-pack/plugins/fleet/public/hooks/use_space_settings_context.test.tsx @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { createFleetTestRendererMock } from '../mock'; +import { ExperimentalFeaturesService } from '../services'; + +import { useGetSpaceSettings } from './use_request'; +import { + SpaceSettingsContextProvider, + useSpaceSettingsContext, +} from './use_space_settings_context'; + +jest.mock('./use_request'); +jest.mock('../services'); + +describe('useSpaceSettingsContext', () => { + function renderHook() { + return createFleetTestRendererMock().renderHook( + () => useSpaceSettingsContext(), + ({ children }: { children: any }) => ( + {children} + ) + ); + } + beforeEach(() => { + jest.mocked(ExperimentalFeaturesService.get).mockReturnValue({ + useSpaceAwareness: true, + } as any); + jest.mocked(useGetSpaceSettings).mockReturnValue({} as any); + }); + it('should return default defaultNamespace if no restrictions', () => { + const res = renderHook(); + expect(res.result.current.defaultNamespace).toBe('default'); + }); + + it('should return restricted defaultNamespace if there is namespace prefix restrictions', () => { + jest.mocked(useGetSpaceSettings).mockReturnValue({ + isInitialLoading: false, + data: { + item: { + allowed_namespace_prefixes: ['test'], + }, + }, + } as any); + const res = renderHook(); + expect(res.result.current.defaultNamespace).toBe('test'); + }); +}); diff --git a/x-pack/plugins/fleet/public/hooks/use_space_settings_context.tsx b/x-pack/plugins/fleet/public/hooks/use_space_settings_context.tsx new file mode 100644 index 0000000000000..665ceca8c3dda --- /dev/null +++ b/x-pack/plugins/fleet/public/hooks/use_space_settings_context.tsx @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { createContext, useContext } from 'react'; + +import { ExperimentalFeaturesService } from '../services'; + +import { useAuthz } from './use_authz'; +import { useGetSpaceSettings } from './use_request'; + +const spaceSettingsContext = createContext<{ + isInitialLoading?: boolean; + allowedNamespacePrefixes: string[]; + defaultNamespace: string; +}>({ + allowedNamespacePrefixes: [], + defaultNamespace: 'default', +}); + +export const SpaceSettingsContextProvider: React.FC<{ + enabled?: boolean; + children?: React.ReactNode; +}> = ({ enabled = true, children }) => { + const useSpaceAwareness = ExperimentalFeaturesService.get()?.useSpaceAwareness ?? false; + const authz = useAuthz(); + const isAllowed = + authz.fleet.allAgentPolicies || + authz.fleet.allSettings || + authz.integrations.writeIntegrationPolicies; + const spaceSettingsReq = useGetSpaceSettings({ + enabled: useSpaceAwareness && enabled && isAllowed, + }); + + const settings = React.useMemo(() => { + return { + isInitialLoading: spaceSettingsReq.isInitialLoading, + allowedNamespacePrefixes: spaceSettingsReq.data?.item.allowed_namespace_prefixes ?? [], + defaultNamespace: spaceSettingsReq.data?.item.allowed_namespace_prefixes?.[0] ?? 'default', + }; + }, [spaceSettingsReq.isInitialLoading, spaceSettingsReq.data]); + + return {children}; +}; + +export function useSpaceSettingsContext() { + return useContext(spaceSettingsContext); +} diff --git a/x-pack/plugins/fleet/public/mock/create_test_renderer.tsx b/x-pack/plugins/fleet/public/mock/create_test_renderer.tsx index ded8351892e2e..3a69f5fdc52e3 100644 --- a/x-pack/plugins/fleet/public/mock/create_test_renderer.tsx +++ b/x-pack/plugins/fleet/public/mock/create_test_renderer.tsx @@ -112,9 +112,17 @@ export const createFleetTestRendererMock = (): TestRenderer => { ); }), HookWrapper, - renderHook: (callback) => { + renderHook: ( + callback, + ExtraWrapper: WrapperComponent = memo(({ children }) => <>{children}) + ) => { + const wrapper: WrapperComponent = ({ children }) => ( + + {children} + + ); return renderHook(callback, { - wrapper: testRendererMocks.HookWrapper, + wrapper, }); }, render: (ui, options) => { @@ -135,6 +143,7 @@ export const createFleetTestRendererMock = (): TestRenderer => { export const createIntegrationsTestRendererMock = (): TestRenderer => { const basePath = '/mock'; const extensions: UIExtensionsStorage = {}; + ExperimentalFeaturesService.init(allowedExperimentalValues); const startServices = createStartServices(basePath); const HookWrapper = memo(({ children }: { children?: React.ReactNode }) => { return ( diff --git a/x-pack/plugins/fleet/public/types/index.ts b/x-pack/plugins/fleet/public/types/index.ts index aeb6d302adaa8..20d94e6d44fa0 100644 --- a/x-pack/plugins/fleet/public/types/index.ts +++ b/x-pack/plugins/fleet/public/types/index.ts @@ -144,6 +144,7 @@ export type { EnrollmentSettingsFleetServerPolicy, GetEnrollmentSettingsRequest, GetEnrollmentSettingsResponse, + GetSpaceSettingsResponse, } from '../../common/types'; export { entries, diff --git a/x-pack/plugins/fleet/server/config.test.ts b/x-pack/plugins/fleet/server/config.test.ts index 7919c9436c9e3..86f05be014d84 100644 --- a/x-pack/plugins/fleet/server/config.test.ts +++ b/x-pack/plugins/fleet/server/config.test.ts @@ -102,11 +102,28 @@ describe('Config schema', () => { }); }).not.toThrow(); }); - it('should allow to specify a URL in xpack.fleet.agentless.api.url ', () => { + it('should not allow to specify a agentless.api.url in xpack.fleet.agentless.api without the tls config ', () => { expect(() => { config.schema.validate({ agentless: { api: { url: 'https://agentless.api.url' } }, }); + }).toThrow(); + }); + + it('should allow to specify agentless.api.url and the tls config in in xpack.fleet.agentless.api', () => { + expect(() => { + config.schema.validate({ + agentless: { + api: { + url: 'https://agentless.api.url', + tls: { + certificate: 'config/certs/agentless.crt', + key: 'config/certs/agentless.key', + ca: 'config/certs/ca.crt', + }, + }, + }, + }); }).not.toThrow(); }); diff --git a/x-pack/plugins/fleet/server/config.ts b/x-pack/plugins/fleet/server/config.ts index 628abfb38d718..5ca34d5b505b3 100644 --- a/x-pack/plugins/fleet/server/config.ts +++ b/x-pack/plugins/fleet/server/config.ts @@ -34,7 +34,11 @@ export const config: PluginConfigDescriptor = { agents: { enabled: true, }, - agentless: true, + agentless: { + api: { + url: true, + }, + }, enableExperimental: true, developer: { maxAgentPoliciesWithInactivityTimeout: true, @@ -146,7 +150,12 @@ export const config: PluginConfigDescriptor = { agentless: schema.maybe( schema.object({ api: schema.object({ - url: schema.maybe(schema.uri({ scheme: ['http', 'https'] })), + url: schema.uri({ scheme: ['http', 'https'] }), + tls: schema.object({ + certificate: schema.string(), + key: schema.string(), + ca: schema.string(), + }), }), }) ), diff --git a/x-pack/plugins/fleet/server/errors/index.ts b/x-pack/plugins/fleet/server/errors/index.ts index 02c72a5d8a25e..e2f8b88380484 100644 --- a/x-pack/plugins/fleet/server/errors/index.ts +++ b/x-pack/plugins/fleet/server/errors/index.ts @@ -51,6 +51,12 @@ export class AgentPolicyError extends FleetError {} export class AgentRequestInvalidError extends FleetError {} export class AgentPolicyInvalidError extends FleetError {} +export class AgentlessAgentCreateError extends FleetError { + constructor(message: string) { + super(`Error creating agentless agent in Fleet, ${message}`); + } +} + export class AgentPolicyNameExistsError extends AgentPolicyError {} export class AgentReassignmentError extends FleetError {} export class PackagePolicyIneligibleForUpgradeError extends FleetError {} diff --git a/x-pack/plugins/fleet/server/plugin.ts b/x-pack/plugins/fleet/server/plugin.ts index fa3eefd90c227..ae65f94238bfa 100644 --- a/x-pack/plugins/fleet/server/plugin.ts +++ b/x-pack/plugins/fleet/server/plugin.ts @@ -41,7 +41,7 @@ import type { SecurityPluginSetup, SecurityPluginStart, } from '@kbn/security-plugin/server'; -import type { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import type { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import type { FieldsMetadataServerSetup } from '@kbn/fields-metadata-plugin/server'; import type { TaskManagerSetupContract, diff --git a/x-pack/plugins/fleet/server/routes/settings/settings_handler.ts b/x-pack/plugins/fleet/server/routes/settings/settings_handler.ts index c959638d0fc6b..4123c2ea37e68 100644 --- a/x-pack/plugins/fleet/server/routes/settings/settings_handler.ts +++ b/x-pack/plugins/fleet/server/routes/settings/settings_handler.ts @@ -42,7 +42,7 @@ export const putSpaceSettingsHandler: FleetRequestHandler< }, spaceId: soClient.getCurrentNamespace(), }); - const settings = await settingsService.getSettings(soClient); + const settings = await getSpaceSettings(soClient.getCurrentNamespace()); const body = { item: settings, }; diff --git a/x-pack/plugins/fleet/server/services/agent_policy.test.ts b/x-pack/plugins/fleet/server/services/agent_policy.test.ts index 5d4c5688d40c7..fe715b8aa57c9 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.test.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.test.ts @@ -4,13 +4,11 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - import { elasticsearchServiceMock, savedObjectsClientMock } from '@kbn/core/server/mocks'; import { SavedObjectsErrorHelpers } from '@kbn/core/server'; import { securityMock } from '@kbn/security-plugin/server/mocks'; import { loggerMock } from '@kbn/logging-mocks'; import type { Logger } from '@kbn/core/server'; - import type { SavedObjectError } from '@kbn/core-saved-objects-common'; import { @@ -115,6 +113,7 @@ function getAgentPolicyCreateMock() { return soClient; } let mockedLogger: jest.Mocked; + describe('Agent policy', () => { beforeEach(() => { mockedLogger = loggerMock.create(); diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index 3dd5c686d98f9..94983e4929883 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -999,7 +999,7 @@ class AgentPolicyService { showInactive: true, perPage: 0, page: 1, - kuery: `${AGENTS_PREFIX}.policy_id:${id} and not status: unenrolled`, + kuery: `${AGENTS_PREFIX}.policy_id:${id}`, }); if (total > 0) { diff --git a/x-pack/plugins/fleet/server/services/agent_policy_create.ts b/x-pack/plugins/fleet/server/services/agent_policy_create.ts index 870cea84b36e1..4d22820b9aa1c 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy_create.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy_create.ts @@ -21,6 +21,8 @@ import { import type { AgentPolicy, NewAgentPolicy } from '../types'; +import { agentlessAgentService } from './agents/agentless_agent'; + import { agentPolicyService, packagePolicyService } from '.'; import { incrementPackageName } from './package_policies'; import { bulkInstallPackages } from './epm/packages'; @@ -170,5 +172,11 @@ export async function createAgentPolicyWithPackages({ await ensureDefaultEnrollmentAPIKeyForAgentPolicy(soClient, esClient, agentPolicy.id); await agentPolicyService.deployPolicy(soClient, agentPolicy.id); + + // Create the agentless agent + if (agentPolicy.supports_agentless) { + await agentlessAgentService.createAgentlessAgent(esClient, soClient, agentPolicy); + } + return agentPolicy; } 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 new file mode 100644 index 0000000000000..376b652ecb163 --- /dev/null +++ b/x-pack/plugins/fleet/server/services/agents/agentless_agent.test.ts @@ -0,0 +1,285 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { elasticsearchServiceMock, savedObjectsClientMock } from '@kbn/core/server/mocks'; +import { securityMock } from '@kbn/security-plugin/server/mocks'; +import { loggerMock } from '@kbn/logging-mocks'; +import type { Logger } from '@kbn/core/server'; + +import axios from 'axios'; + +import { AgentlessAgentCreateError } from '../../errors'; +import type { AgentPolicy, NewAgentPolicy } from '../../types'; + +import { appContextService } from '../app_context'; +import { listEnrollmentApiKeys } from '../api_keys'; +import { listFleetServerHosts } from '../fleet_server_host'; + +import { agentlessAgentService } from './agentless_agent'; + +jest.mock('axios', () => jest.fn()); +jest.mock('../fleet_server_host'); +jest.mock('../api_keys'); +jest.mock('../output'); +jest.mock('../download_source'); +jest.mock('../agent_policy_update'); +jest.mock('../package_policy'); +jest.mock('../app_context'); +jest.mock('../audit_logging'); +jest.mock('../agent_policies/full_agent_policy'); +jest.mock('../agent_policies/outputs_helpers'); + +const mockedAppContextService = appContextService as jest.Mocked; +mockedAppContextService.getSecuritySetup.mockImplementation(() => ({ + ...securityMock.createSetup(), +})); + +const mockedListEnrollmentApiKeys = listEnrollmentApiKeys as jest.Mock< + ReturnType +>; +const mockedListFleetServerHosts = listFleetServerHosts as jest.Mock< + ReturnType +>; + +function getAgentPolicyCreateMock() { + const soClient = savedObjectsClientMock.create(); + soClient.create.mockImplementation(async (type, attributes) => { + return { + attributes: attributes as unknown as NewAgentPolicy, + id: 'mocked', + type: 'mocked', + references: [], + }; + }); + return soClient; +} +let mockedLogger: jest.Mocked; + +jest.mock('@kbn/server-http-tools', () => ({ + ...jest.requireActual('@kbn/server-http-tools'), + SslConfig: jest.fn().mockImplementation(({ certificate, key, certificateAuthorities }) => ({ + certificate, + key, + certificateAuthorities: [certificateAuthorities], + })), +})); + +describe('Agentless Agent service', () => { + beforeEach(() => { + mockedLogger = loggerMock.create(); + mockedAppContextService.getLogger.mockReturnValue(mockedLogger); + mockedAppContextService.getExperimentalFeatures.mockReturnValue({ agentless: false } as any); + (axios as jest.MockedFunction).mockReset(); + jest.clearAllMocks(); + }); + + afterEach(() => { + jest.resetAllMocks(); + }); + + it('should throw AgentlessAgentCreateError if agentless policy does not support_agentless', async () => { + const soClient = getAgentPolicyCreateMock(); + // ignore unrelated unique name constraint + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isCloudEnabled: true } as any); + + await expect( + agentlessAgentService.createAgentlessAgent(esClient, soClient, { + id: 'mocked', + name: 'agentless agent policy', + namespace: 'default', + supports_agentless: false, + } as AgentPolicy) + ).rejects.toThrowError( + new AgentlessAgentCreateError('Agentless agent policy does not have agentless enabled') + ); + }); + + it('should throw AgentlessAgentCreateError if cloud is not enabled', async () => { + const soClient = getAgentPolicyCreateMock(); + // ignore unrelated unique name constraint + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isCloudEnabled: false } as any); + + await expect( + agentlessAgentService.createAgentlessAgent(esClient, soClient, { + id: 'mocked', + name: 'agentless agent policy', + namespace: 'default', + supports_agentless: true, + } as AgentPolicy) + ).rejects.toThrowError(new AgentlessAgentCreateError('Agentless agent not supported')); + }); + + it('should throw AgentlessAgentCreateError if agentless configuration is not found', async () => { + const soClient = getAgentPolicyCreateMock(); + // ignore unrelated unique name constraint + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + jest.spyOn(appContextService, 'getConfig').mockReturnValue({} as any); + jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isCloudEnabled: true } as any); + + await expect( + agentlessAgentService.createAgentlessAgent(esClient, soClient, { + id: 'mocked', + name: 'agentless agent policy', + namespace: 'default', + supports_agentless: true, + } as AgentPolicy) + ).rejects.toThrowError(new AgentlessAgentCreateError('missing agentless configuration')); + }); + it('should throw AgentlessAgentCreateError if fleet hosts are not found', async () => { + const soClient = getAgentPolicyCreateMock(); + // ignore unrelated unique name constraint + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + jest.spyOn(appContextService, 'getConfig').mockReturnValue({ + agentless: { + api: { + url: 'http://api.agentless.com/api/v1/ess', + tls: { + certificate: '/path/to/cert', + key: '/path/to/key', + }, + }, + }, + } as any); + jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isCloudEnabled: true } as any); + mockedListFleetServerHosts.mockResolvedValue({ items: [] } as any); + mockedListEnrollmentApiKeys.mockResolvedValue({ + items: [ + { + id: 'mocked', + policy_id: 'mocked', + api_key: 'mocked', + }, + ], + } as any); + + await expect( + agentlessAgentService.createAgentlessAgent(esClient, soClient, { + id: 'mocked', + name: 'agentless agent policy', + namespace: 'default', + supports_agentless: true, + } as AgentPolicy) + ).rejects.toThrowError(new AgentlessAgentCreateError('missing Fleet server host')); + }); + + it('should throw AgentlessAgentCreateError if enrollment tokens are not found', async () => { + const soClient = getAgentPolicyCreateMock(); + // ignore unrelated unique name constraint + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + jest.spyOn(appContextService, 'getConfig').mockReturnValue({ + agentless: { + api: { + url: 'http://api.agentless.com/api/v1/ess', + tls: { + certificate: '/path/to/cert', + key: '/path/to/key', + }, + }, + }, + } as any); + jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isCloudEnabled: true } as any); + mockedListFleetServerHosts.mockResolvedValue({ + items: [ + { + id: 'mocked', + host: 'http://fleetserver:8220', + active: true, + is_default: true, + }, + ], + } as any); + mockedListEnrollmentApiKeys.mockResolvedValue({ + items: [], + } as any); + + await expect( + agentlessAgentService.createAgentlessAgent(esClient, soClient, { + id: 'mocked', + name: 'agentless agent policy', + namespace: 'default', + supports_agentless: true, + } as AgentPolicy) + ).rejects.toThrowError(new AgentlessAgentCreateError('missing Fleet enrollment token')); + }); + + it('should create agentless agent', async () => { + const returnValue = { + id: 'mocked', + regional_id: 'mocked', + }; + + (axios as jest.MockedFunction).mockResolvedValueOnce(returnValue); + const soClient = getAgentPolicyCreateMock(); + // ignore unrelated unique name constraint + const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + jest.spyOn(appContextService, 'getConfig').mockReturnValue({ + agentless: { + api: { + url: 'http://api.agentless.com/api/v1/ess', + tls: { + certificate: '/path/to/cert', + key: '/path/to/key', + ca: '/path/to/ca', + }, + }, + }, + } as any); + jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isCloudEnabled: true } as any); + jest + .spyOn(appContextService, 'getKibanaVersion') + .mockReturnValue('mocked-kibana-version-infinite'); + mockedListFleetServerHosts.mockResolvedValue({ + items: [ + { + id: 'mocked-fleet-server-id', + host: 'http://fleetserver:8220', + active: true, + is_default: true, + host_urls: ['http://fleetserver:8220'], + }, + ], + } as any); + mockedListEnrollmentApiKeys.mockResolvedValue({ + items: [ + { + id: 'mocked-fleet-enrollment-token-id', + policy_id: 'mocked-fleet-enrollment-policy-id', + api_key: 'mocked-fleet-enrollment-api-key', + }, + ], + } as any); + + const createAgentlessAgentReturnValue = await agentlessAgentService.createAgentlessAgent( + esClient, + soClient, + { + id: 'mocked-agentless-agent-policy-id', + name: 'agentless agent policy', + namespace: 'default', + supports_agentless: true, + } as AgentPolicy + ); + + expect(axios).toHaveBeenCalledTimes(1); + expect(createAgentlessAgentReturnValue).toEqual(returnValue); + expect(axios).toHaveBeenCalledWith( + expect.objectContaining({ + data: expect.objectContaining({ + fleet_token: 'mocked-fleet-enrollment-api-key', + fleet_url: 'http://fleetserver:8220', + policy_id: 'mocked-agentless-agent-policy-id', + stack_version: 'mocked-kibana-version-infinite', + }), + headers: expect.anything(), + httpsAgent: expect.anything(), + method: 'POST', + url: 'http://api.agentless.com/api/v1/ess/deployments', + }) + ); + }); +}); diff --git a/x-pack/plugins/fleet/server/services/agents/agentless_agent.ts b/x-pack/plugins/fleet/server/services/agents/agentless_agent.ts new file mode 100644 index 0000000000000..2e97ab335a8a4 --- /dev/null +++ b/x-pack/plugins/fleet/server/services/agents/agentless_agent.ts @@ -0,0 +1,166 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import https from 'https'; + +import type { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server'; +import { SslConfig, sslSchema } from '@kbn/server-http-tools'; + +import type { AxiosError } from 'axios'; +import axios from 'axios'; + +import { SO_SEARCH_LIMIT } from '../../constants'; +import type { AgentPolicy } from '../../types'; +import type { AgentlessApiResponse } from '../../../common/types'; +import { AgentlessAgentCreateError } from '../../errors'; + +import { appContextService } from '../app_context'; + +import { listEnrollmentApiKeys } from '../api_keys'; +import { listFleetServerHosts } from '../fleet_server_host'; + +class AgentlessAgentService { + public async createAgentlessAgent( + esClient: ElasticsearchClient, + soClient: SavedObjectsClientContract, + agentlessAgentPolicy: AgentPolicy + ) { + const logger = appContextService.getLogger(); + logger.debug(`Creating agentless agent ${agentlessAgentPolicy.id}`); + + if (!appContextService.getCloud()?.isCloudEnabled) { + logger.error('Creating agentless agent not supported in non-cloud environments'); + throw new AgentlessAgentCreateError('Agentless agent not supported'); + } + if (!agentlessAgentPolicy.supports_agentless) { + logger.error('Agentless agent policy does not have agentless enabled'); + throw new AgentlessAgentCreateError('Agentless agent policy does not have agentless enabled'); + } + + const agentlessConfig = appContextService.getConfig()?.agentless; + if (!agentlessConfig) { + logger.error('Missing agentless configuration'); + throw new AgentlessAgentCreateError('missing agentless configuration'); + } + + const policyId = agentlessAgentPolicy.id; + const { fleetUrl, fleetToken } = await this.getFleetUrlAndTokenForAgentlessAgent( + esClient, + policyId, + soClient + ); + + logger.debug(`Creating agentless agent with fleetUrl ${fleetUrl} and fleetToken ${fleetToken}`); + + logger.debug(`Creating agentless agent with TLS config with certificate: ${agentlessConfig.api.tls.certificate}, + and key: ${agentlessConfig.api.tls.key}`); + + const tlsConfig = new SslConfig( + sslSchema.validate({ + enabled: true, + certificate: agentlessConfig.api.tls.certificate, + key: agentlessConfig.api.tls.key, + certificateAuthorities: agentlessConfig.api.tls.ca, + }) + ); + + const requestConfig = { + url: `${agentlessConfig.api.url}/deployments`, + data: { + policy_id: policyId, + fleet_url: fleetUrl, + fleet_token: fleetToken, + stack_version: appContextService.getKibanaVersion(), + }, + method: 'POST', + headers: { + 'Content-type': 'application/json', + }, + httpsAgent: new https.Agent({ + rejectUnauthorized: tlsConfig.rejectUnauthorized, + cert: tlsConfig.certificate, + key: tlsConfig.key, + ca: tlsConfig.certificateAuthorities, + }), + }; + + logger.debug( + `Creating agentless agent with request config ${JSON.stringify({ + ...requestConfig, + httpsAgent: { + ...requestConfig.httpsAgent, + options: { + ...requestConfig.httpsAgent.options, + cert: requestConfig.httpsAgent.options.cert ? 'REDACTED' : undefined, + key: requestConfig.httpsAgent.options.key ? 'REDACTED' : undefined, + ca: requestConfig.httpsAgent.options.ca ? 'REDACTED' : undefined, + }, + }, + })}` + ); + + const response = await axios(requestConfig).catch( + (error: Error | AxiosError) => { + if (!axios.isAxiosError(error)) { + logger.error(`Creating agentless failed with an error ${error}`); + throw new AgentlessAgentCreateError(error.message); + } + if (error.response) { + logger.error( + `Creating agentless failed with a response status code that falls out of the range of 2xx: ${error.response.status} ${error.response.statusText} ${requestConfig.data}` + ); + throw new AgentlessAgentCreateError( + `the Agentless API could not create the agentless agent` + ); + } else if (error.request) { + logger.error( + `Creating agentless failed to receive a response from the Agentless API ${JSON.stringify( + error.cause + )}` + ); + throw new AgentlessAgentCreateError(`no response received from the Agentless API`); + } else { + logger.error(`Creating agentless failed to create the request ${error.cause}`); + throw new AgentlessAgentCreateError('the request could not be created'); + } + } + ); + + logger.debug(`Created an agentless agent ${response}`); + return response; + } + + private async getFleetUrlAndTokenForAgentlessAgent( + esClient: ElasticsearchClient, + policyId: string, + soClient: SavedObjectsClientContract + ) { + const { items: enrollmentApiKeys } = await listEnrollmentApiKeys(esClient, { + perPage: SO_SEARCH_LIMIT, + showInactive: true, + kuery: `policy_id:"${policyId}"`, + }); + + const { items: fleetHosts } = await listFleetServerHosts(soClient); + // Tech Debt: change this when we add the internal fleet server config to use the internal fleet server host + // https://github.com/elastic/security-team/issues/9695 + const defaultFleetHost = + fleetHosts.length === 1 ? fleetHosts[0] : fleetHosts.find((host) => host.is_default); + + if (!defaultFleetHost) { + throw new AgentlessAgentCreateError('missing Fleet server host'); + } + if (!enrollmentApiKeys.length) { + throw new AgentlessAgentCreateError('missing Fleet enrollment token'); + } + const fleetToken = enrollmentApiKeys[0].api_key; + const fleetUrl = defaultFleetHost?.host_urls[0]; + return { fleetUrl, fleetToken }; + } +} + +export const agentlessAgentService = new AgentlessAgentService(); diff --git a/x-pack/plugins/fleet/server/services/agents/crud.test.ts b/x-pack/plugins/fleet/server/services/agents/crud.test.ts index 3716319991be5..d51b0d52d4d7c 100644 --- a/x-pack/plugins/fleet/server/services/agents/crud.test.ts +++ b/x-pack/plugins/fleet/server/services/agents/crud.test.ts @@ -7,6 +7,7 @@ import { errors } from '@elastic/elasticsearch'; import type { ElasticsearchClient } from '@kbn/core/server'; import { elasticsearchServiceMock, savedObjectsClientMock } from '@kbn/core/server/mocks'; +import { toElasticsearchQuery } from '@kbn/es-query'; import { AGENTS_INDEX } from '../../constants'; import { createAppContextStartContractMock } from '../../mocks'; @@ -22,6 +23,7 @@ import { getAgentTags, openPointInTime, updateAgent, + _joinFilters, } from './crud'; jest.mock('../audit_logging'); @@ -135,20 +137,6 @@ describe('Agents CRUD test', () => { expect(searchMock).toHaveBeenCalledWith( expect.objectContaining({ aggs: { tags: { terms: { field: 'tags', size: 10000 } } }, - body: { - query: { - bool: { - minimum_should_match: 1, - should: [ - { - match: { - policy_id: '123', - }, - }, - ], - }, - }, - }, index: '.fleet-agents', size: 0, fields: ['status'], @@ -157,6 +145,12 @@ describe('Agents CRUD test', () => { }, }) ); + + expect(searchMock.mock.calls.at(-1)[0].body.query).toEqual( + toElasticsearchQuery( + _joinFilters(['fleet-agents.policy_id: 123', 'NOT status:unenrolled'])! + ) + ); }); }); @@ -415,6 +409,66 @@ describe('Agents CRUD test', () => { }); expect(searchMock.mock.calls.at(-1)[0].sort).toEqual([{ policy_id: { order: 'desc' } }]); }); + + describe('status filters', () => { + beforeEach(() => { + searchMock.mockImplementationOnce(() => Promise.resolve(getEsResponse([], 0, 'online'))); + }); + it('should add inactive and unenrolled filter', async () => { + await getAgentsByKuery(esClientMock, soClientMock, { + showInactive: false, + kuery: '', + }); + + expect(searchMock.mock.calls.at(-1)[0].query).toEqual( + toElasticsearchQuery(_joinFilters(['NOT (status:inactive)', 'NOT status:unenrolled'])!) + ); + }); + + it('should add unenrolled filter', async () => { + await getAgentsByKuery(esClientMock, soClientMock, { + showInactive: true, + kuery: '', + }); + + expect(searchMock.mock.calls.at(-1)[0].query).toEqual( + toElasticsearchQuery(_joinFilters(['NOT status:unenrolled'])!) + ); + }); + + it('should not add unenrolled filter', async () => { + await getAgentsByKuery(esClientMock, soClientMock, { + showInactive: true, + kuery: 'status:unenrolled', + }); + + expect(searchMock.mock.calls.at(-1)[0].query).toEqual( + toElasticsearchQuery(_joinFilters(['status:unenrolled'])!) + ); + }); + + it('should add inactive filter', async () => { + await getAgentsByKuery(esClientMock, soClientMock, { + showInactive: false, + kuery: 'status:*', + }); + + expect(searchMock.mock.calls.at(-1)[0].query).toEqual( + toElasticsearchQuery(_joinFilters(['status:*', 'NOT status:inactive'])!) + ); + }); + + it('should not add inactive filter', async () => { + await getAgentsByKuery(esClientMock, soClientMock, { + showInactive: true, + kuery: 'status:*', + }); + + expect(searchMock.mock.calls.at(-1)[0].query).toEqual( + toElasticsearchQuery(_joinFilters(['status:*'])!) + ); + }); + }); }); describe('update', () => { diff --git a/x-pack/plugins/fleet/server/services/agents/crud.ts b/x-pack/plugins/fleet/server/services/agents/crud.ts index e6bcd5f954f2e..368d5c0df834e 100644 --- a/x-pack/plugins/fleet/server/services/agents/crud.ts +++ b/x-pack/plugins/fleet/server/services/agents/crud.ts @@ -34,8 +34,12 @@ import { searchHitToAgent, agentSOAttributesToFleetServerAgentDoc } from './help import { buildAgentStatusRuntimeField } from './build_status_runtime_field'; import { getLatestAvailableAgentVersion } from './versions'; -const INACTIVE_AGENT_CONDITION = `status:inactive OR status:unenrolled`; +const INACTIVE_AGENT_CONDITION = `status:inactive`; const ACTIVE_AGENT_CONDITION = `NOT (${INACTIVE_AGENT_CONDITION})`; +const ENROLLED_AGENT_CONDITION = `NOT status:unenrolled`; + +const includeUnenrolled = (kuery?: string) => + kuery?.toLowerCase().includes('status:*') || kuery?.toLowerCase().includes('status:unenrolled'); export function _joinFilters( filters: Array @@ -157,6 +161,9 @@ export async function getAgentTags( if (showInactive === false) { filters.push(ACTIVE_AGENT_CONDITION); } + if (!includeUnenrolled(kuery)) { + filters.push(ENROLLED_AGENT_CONDITION); + } const kueryNode = _joinFilters(filters); const body = kueryNode ? { query: toElasticsearchQuery(kueryNode) } : {}; @@ -184,33 +191,6 @@ export async function getAgentTags( } } -export function getElasticsearchQuery( - kuery: string, - showInactive = false, - includeHosted = false, - hostedPolicies: string[] = [], - extraFilters: string[] = [] -): estypes.QueryDslQueryContainer | undefined { - const filters = []; - - if (kuery && kuery !== '') { - filters.push(kuery); - } - - if (showInactive === false) { - filters.push(ACTIVE_AGENT_CONDITION); - } - - if (!includeHosted && hostedPolicies.length > 0) { - filters.push('NOT (policy_id:{policyIds})'.replace('{policyIds}', hostedPolicies.join(','))); - } - - filters.push(...extraFilters); - - const kueryNode = _joinFilters(filters); - return kueryNode ? toElasticsearchQuery(kueryNode) : undefined; -} - export async function getAgentsByKuery( esClient: ElasticsearchClient, soClient: SavedObjectsClientContract, @@ -264,6 +244,9 @@ export async function getAgentsByKuery( if (showInactive === false) { filters.push(ACTIVE_AGENT_CONDITION); } + if (!includeUnenrolled(kuery)) { + filters.push(ENROLLED_AGENT_CONDITION); + } const kueryNode = _joinFilters(filters); diff --git a/x-pack/plugins/fleet/server/services/package_policy.test.ts b/x-pack/plugins/fleet/server/services/package_policy.test.ts index 23a8c720b09a1..a62a5048ec567 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.test.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.test.ts @@ -5188,6 +5188,39 @@ describe('getUpgradeDryRunDiff', () => { }, ]); }); + + it('should omit spaceId when upgrading package policies with spaceId', async () => { + savedObjectsClient.get.mockImplementation((type, id) => + Promise.resolve({ + id, + type: 'abcd', + references: [], + version: '0.9.0', + attributes: { ...createPackagePolicyMock(), name: id, spaceId: 'test' }, + }) + ); + const elasticsearchClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + const res = await packagePolicyService.upgrade(savedObjectsClient, elasticsearchClient, [ + 'package-policy-id-test-spaceId', + ]); + + expect(res).toEqual([ + { + id: 'package-policy-id-test-spaceId', + name: 'package-policy-id-test-spaceId', + success: true, + }, + ]); + + expect(savedObjectsClient.update).toBeCalledWith( + 'ingest-package-policies', + 'package-policy-id-test-spaceId', + expect.not.objectContaining({ + spaceId: expect.anything(), + }), + expect.anything() + ); + }); }); describe('_applyIndexPrivileges()', () => { diff --git a/x-pack/plugins/fleet/server/services/package_policy.ts b/x-pack/plugins/fleet/server/services/package_policy.ts index 794269ba78ca6..8ee996c69e523 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.ts @@ -1541,7 +1541,7 @@ class PackagePolicyClientImpl implements PackagePolicyClient { ) { const updatePackagePolicy = updatePackageInputs( { - ...omit(packagePolicy, 'id'), + ...omit(packagePolicy, 'id', 'spaceId'), inputs: packagePolicy.inputs, package: { ...packagePolicy.package!, @@ -1626,7 +1626,7 @@ class PackagePolicyClientImpl implements PackagePolicyClient { ): Promise { const updatedPackagePolicy = updatePackageInputs( { - ...omit(packagePolicy, 'id'), + ...omit(packagePolicy, 'id', 'spaceId'), inputs: packagePolicy.inputs, package: { ...packagePolicy.package!, @@ -1881,6 +1881,7 @@ class PackagePolicyClientImpl implements PackagePolicyClient { const omitted = { ...omit(result, [ 'id', + 'spaceId', 'version', 'revision', 'updated_at', diff --git a/x-pack/plugins/fleet/tsconfig.json b/x-pack/plugins/fleet/tsconfig.json index b45bd90010b42..62ee9dce52994 100644 --- a/x-pack/plugins/fleet/tsconfig.json +++ b/x-pack/plugins/fleet/tsconfig.json @@ -111,5 +111,7 @@ "@kbn/core-saved-objects-utils-server", "@kbn/integration-assistant-plugin", "@kbn/core-security-server-mocks", + "@kbn/server-http-tools", + "@kbn/avc-banner", ] } diff --git a/x-pack/plugins/graph/public/components/_sidebar.scss b/x-pack/plugins/graph/public/components/_sidebar.scss index f835eeac10c0a..d87092b7dc32a 100644 --- a/x-pack/plugins/graph/public/components/_sidebar.scss +++ b/x-pack/plugins/graph/public/components/_sidebar.scss @@ -20,7 +20,7 @@ .gphSidebar__header { margin-top: $euiSizeS; color: $euiColorEmptyShade; - background-color: $euiColorDarkShade; + background-color: $euiColorDarkestShade; padding: $euiSizeXS; border-radius: $euiBorderRadius; margin-bottom: $euiSizeXS; @@ -63,6 +63,9 @@ line-height: $euiLineHeight; margin: $euiSizeXS 0; cursor: pointer; + width: 100%; + display: block; + text-align: left; > * { vertical-align: middle; diff --git a/x-pack/plugins/graph/public/components/control_panel/selected_node_item.tsx b/x-pack/plugins/graph/public/components/control_panel/selected_node_item.tsx index 0dfc01d64873c..bff32d0d21113 100644 --- a/x-pack/plugins/graph/public/components/control_panel/selected_node_item.tsx +++ b/x-pack/plugins/graph/public/components/control_panel/selected_node_item.tsx @@ -39,7 +39,7 @@ export const SelectedNodeItem = ({ const offset = fixIconOffset(node); return ( - + ); }; diff --git a/x-pack/plugins/graph/server/plugin.ts b/x-pack/plugins/graph/server/plugin.ts index 88e45bc007e47..27d3577e047a2 100644 --- a/x-pack/plugins/graph/server/plugin.ts +++ b/x-pack/plugins/graph/server/plugin.ts @@ -10,7 +10,7 @@ import { Plugin, CoreSetup, CoreStart, PluginInitializerContext } from '@kbn/cor import { DEFAULT_APP_CATEGORIES } from '@kbn/core/server'; import { LicensingPluginSetup, LicensingPluginStart } from '@kbn/licensing-plugin/server'; import { HomeServerPluginSetup } from '@kbn/home-plugin/server'; -import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { ContentManagementServerSetup } from '@kbn/content-management-plugin/server'; import { LicenseState } from './lib/license_state'; import { registerSearchRoute } from './routes/search'; diff --git a/x-pack/plugins/index_lifecycle_management/server/types.ts b/x-pack/plugins/index_lifecycle_management/server/types.ts index dcffbaded6b5c..27a6c4cbd52b9 100644 --- a/x-pack/plugins/index_lifecycle_management/server/types.ts +++ b/x-pack/plugins/index_lifecycle_management/server/types.ts @@ -7,7 +7,7 @@ import { IRouter } from '@kbn/core/server'; -import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { LicensingPluginSetup } from '@kbn/licensing-plugin/server'; import { IndexManagementPluginSetup } from '@kbn/index-management-plugin/server'; import { License } from './services'; diff --git a/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/index_details_page.helpers.ts b/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/index_details_page.helpers.ts index d80b08b96dacc..7a55439dd0f92 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/index_details_page.helpers.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/index_details_page.helpers.ts @@ -107,6 +107,7 @@ export interface IndexDetailsPageTestBed extends TestBed { getDataStreamDetailsContent: () => string; reloadDataStreamDetails: () => Promise; addDocCodeBlockExists: () => boolean; + indexErrorCalloutExists: () => boolean; }; }; } @@ -196,6 +197,9 @@ export const setup = async ({ addDocCodeBlockExists: () => { return exists('codeBlockControlsPanel'); }, + indexErrorCalloutExists: () => { + return exists('indexErrorCallout'); + }, }; const mappings = { diff --git a/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/index_details_page.test.tsx b/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/index_details_page.test.tsx index 298ad1f9af02c..c4d366daa1d29 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/index_details_page.test.tsx +++ b/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/index_details_page.test.tsx @@ -25,6 +25,7 @@ import { testIndexEditableSettingsAll, testIndexEditableSettingsLimited, testIndexMappings, + testIndexMappingsWithSemanticText, testIndexMock, testIndexName, testIndexSettings, @@ -103,8 +104,8 @@ describe('', () => { }); it('resends a request when reload button is clicked', async () => { - // already sent 2 requests while setting up the component - const numberOfRequests = 2; + // already sent 4 requests while setting up the component + const numberOfRequests = 4; expect(httpSetup.get).toHaveBeenCalledTimes(numberOfRequests); await testBed.actions.errorSection.clickReloadButton(); expect(httpSetup.get).toHaveBeenCalledTimes(numberOfRequests + 1); @@ -112,7 +113,7 @@ describe('', () => { it('renders an error section when no index name is provided', async () => { // already sent 2 requests while setting up the component - const numberOfRequests = 2; + const numberOfRequests = 4; expect(httpSetup.get).toHaveBeenCalledTimes(numberOfRequests); await act(async () => { testBed = await setup({ httpSetup, initialEntry: '/indices/index_details' }); @@ -124,6 +125,80 @@ describe('', () => { }); }); + describe('Semantic text index errors', () => { + it('does not render an error callout by default', () => { + expect(testBed.actions.overview.indexErrorCalloutExists()).toBe(false); + }); + it('renders an error callout when the mapping contains semantic text errors', async () => { + httpRequestsMockHelpers.setLoadIndexMappingResponse( + testIndexName, + testIndexMappingsWithSemanticText.mappings + ); + await act(async () => { + testBed = await setup({ + httpSetup, + dependencies: { + docLinks: { + links: { + ml: '', + enterpriseSearch: '', + }, + }, + core: { + application: { capabilities: { ml: { canGetTrainedModels: true } } }, + }, + plugins: { + ml: { + mlApi: { + trainedModels: { + getModelsDownloadStatus: jest.fn().mockResolvedValue({}), + getTrainedModels: jest.fn().mockResolvedValue([ + { + model_id: '.elser_model_2', + model_type: 'pytorch', + model_package: { + packaged_model_id: '.elser_model_2', + model_repository: 'https://ml-models.elastic.co', + minimum_version: '11.0.0', + size: 438123914, + sha256: '', + metadata: {}, + tags: [], + vocabulary_file: 'elser_model_2.vocab.json', + }, + description: 'Elastic Learned Sparse EncodeR v2', + tags: ['elastic'], + }, + ]), + getTrainedModelStats: jest.fn().mockResolvedValue({ + count: 1, + trained_model_stats: [ + { + model_id: '.elser_model_2', + + deployment_stats: { + deployment_id: '.elser_model_2', + model_id: '.elser_model_2', + threads_per_allocation: 1, + number_of_allocations: 1, + queue_capacity: 1024, + state: 'started', + }, + }, + ], + }), + }, + }, + }, + }, + }, + }); + }); + testBed.component.update(); + expect(testBed.actions.overview.indexErrorCalloutExists()).toBe(true); + }); + }); + describe('Stats tab', () => { it('updates the breadcrumbs to index details stats', async () => { await testBed.actions.clickIndexDetailsTab(IndexDetailsSection.Stats); @@ -209,8 +284,8 @@ describe('', () => { }); it('resends a request when reload button is clicked', async () => { - // already sent 3 requests while setting up the component - const numberOfRequests = 3; + // already sent 7 requests while setting up the component + const numberOfRequests = 7; expect(httpSetup.get).toHaveBeenCalledTimes(numberOfRequests); await testBed.actions.stats.clickErrorReloadButton(); expect(httpSetup.get).toHaveBeenCalledTimes(numberOfRequests + 1); @@ -219,7 +294,7 @@ describe('', () => { }); it('loads index details from the API', async () => { - expect(httpSetup.get).toHaveBeenLastCalledWith( + expect(httpSetup.get).toHaveBeenCalledWith( `${INTERNAL_API_BASE_PATH}/indices/${testIndexName}`, requestOptions ); @@ -382,8 +457,8 @@ describe('', () => { `Data streamUnable to load data stream detailsReloadLast update` ); - // already sent 3 requests while setting up the component - const numberOfRequests = 3; + // already sent 7 requests while setting up the component + const numberOfRequests = 7; expect(httpSetup.get).toHaveBeenCalledTimes(numberOfRequests); await testBed.actions.overview.reloadDataStreamDetails(); expect(httpSetup.get).toHaveBeenCalledTimes(numberOfRequests + 1); @@ -612,7 +687,7 @@ describe('', () => { body: '{"name":{"type":"text"}}', }); - expect(httpSetup.get).toHaveBeenCalledTimes(5); + expect(httpSetup.get).toHaveBeenCalledTimes(9); expect(httpSetup.get).toHaveBeenLastCalledWith( `${API_BASE_PATH}/mapping/${testIndexName}`, requestOptions @@ -792,8 +867,8 @@ describe('', () => { }); it('resends a request when reload button is clicked', async () => { - // already sent 4 requests while setting up the component - const numberOfRequests = 4; + // already sent 8 requests while setting up the component + const numberOfRequests = 8; expect(httpSetup.get).toHaveBeenCalledTimes(numberOfRequests); await testBed.actions.mappings.clickErrorReloadButton(); expect(httpSetup.get).toHaveBeenCalledTimes(numberOfRequests + 1); @@ -890,8 +965,8 @@ describe('', () => { }); it('resends a request when reload button is clicked', async () => { - // already sent 3 requests while setting up the component - const numberOfRequests = 3; + // already sent 7 requests while setting up the component + const numberOfRequests = 7; expect(httpSetup.get).toHaveBeenCalledTimes(numberOfRequests); await testBed.actions.settings.clickErrorReloadButton(); expect(httpSetup.get).toHaveBeenCalledTimes(numberOfRequests + 1); @@ -942,7 +1017,7 @@ describe('', () => { }); it('reloads the settings after an update', async () => { - const numberOfRequests = 2; + const numberOfRequests = 4; expect(httpSetup.get).toHaveBeenCalledTimes(numberOfRequests); const updatedSettings = { ...testIndexEditableSettingsAll, 'index.priority': '2' }; await testBed.actions.settings.updateCodeEditorContent(JSON.stringify(updatedSettings)); @@ -1004,8 +1079,8 @@ describe('', () => { }); it('closes an index', async () => { - // already sent 1 request while setting up the component - const numberOfRequests = 1; + // already sent 3 requests while setting up the component + const numberOfRequests = 3; expect(httpSetup.get).toHaveBeenCalledTimes(numberOfRequests); await testBed.actions.contextMenu.clickManageIndexButton(); @@ -1027,8 +1102,8 @@ describe('', () => { }); testBed.component.update(); - // already sent 2 requests while setting up the component - const numberOfRequests = 2; + // already sent 6 requests while setting up the component + const numberOfRequests = 6; expect(httpSetup.get).toHaveBeenCalledTimes(numberOfRequests); await testBed.actions.contextMenu.clickManageIndexButton(); @@ -1040,8 +1115,8 @@ describe('', () => { }); it('forcemerges an index', async () => { - // already sent 1 request while setting up the component - const numberOfRequests = 1; + // already sent 3 request while setting up the component + const numberOfRequests = 3; expect(httpSetup.get).toHaveBeenCalledTimes(numberOfRequests); await testBed.actions.contextMenu.clickManageIndexButton(); @@ -1054,8 +1129,8 @@ describe('', () => { }); it('refreshes an index', async () => { - // already sent 1 request while setting up the component - const numberOfRequests = 1; + // already sent 3 request while setting up the component + const numberOfRequests = 3; expect(httpSetup.get).toHaveBeenCalledTimes(numberOfRequests); await testBed.actions.contextMenu.clickManageIndexButton(); @@ -1067,8 +1142,8 @@ describe('', () => { }); it(`clears an index's cache`, async () => { - // already sent 1 request while setting up the component - const numberOfRequests = 1; + // already sent 3 request while setting up the component + const numberOfRequests = 3; expect(httpSetup.get).toHaveBeenCalledTimes(numberOfRequests); await testBed.actions.contextMenu.clickManageIndexButton(); @@ -1080,8 +1155,8 @@ describe('', () => { }); it(`flushes an index`, async () => { - // already sent 1 request while setting up the component - const numberOfRequests = 1; + // already sent 3 requests while setting up the component + const numberOfRequests = 3; expect(httpSetup.get).toHaveBeenCalledTimes(numberOfRequests); await testBed.actions.contextMenu.clickManageIndexButton(); @@ -1095,7 +1170,7 @@ describe('', () => { it(`deletes an index`, async () => { jest.spyOn(testBed.routerMock.history, 'push'); // already sent 1 request while setting up the component - const numberOfRequests = 1; + const numberOfRequests = 3; expect(httpSetup.get).toHaveBeenCalledTimes(numberOfRequests); await testBed.actions.contextMenu.clickManageIndexButton(); @@ -1120,8 +1195,8 @@ describe('', () => { }); testBed.component.update(); - // already sent 1 request while setting up the component - const numberOfRequests = 2; + // already sent 6 requests while setting up the component + const numberOfRequests = 6; expect(httpSetup.get).toHaveBeenCalledTimes(numberOfRequests); await testBed.actions.contextMenu.clickManageIndexButton(); @@ -1154,7 +1229,7 @@ describe('', () => { testBed.component.update(); }); it('loads the index details with the encoded index name', () => { - expect(httpSetup.get).toHaveBeenLastCalledWith( + expect(httpSetup.get).toHaveBeenCalledWith( `${INTERNAL_API_BASE_PATH}/indices/${encodeURIComponent(percentSignName)}`, requestOptions ); diff --git a/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/mocks.ts b/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/mocks.ts index abcf0d481431e..c4fe4cf19014b 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/mocks.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/mocks.ts @@ -42,6 +42,22 @@ export const testIndexMappings = { }, }; +export const testIndexMappingsWithSemanticText = { + mappings: { + dynamic: 'false', + dynamic_templates: [], + properties: { + '@timestamp': { + type: 'date', + }, + semantic_text: { + type: 'semantic_text', + inference_id: 'inference_id', + }, + }, + }, +}; + // Mocking partial index settings response export const testIndexSettings = { settings: { diff --git a/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/trained_models_deployment_modal.test.tsx b/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/trained_models_deployment_modal.test.tsx index cd9d099ee92f8..b7e246614fd38 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/trained_models_deployment_modal.test.tsx +++ b/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/trained_models_deployment_modal.test.tsx @@ -107,7 +107,8 @@ const defaultState = { } as any; const setErrorsInTrainedModelDeployment = jest.fn().mockReturnValue(undefined); -const fetchData = jest.fn().mockReturnValue(undefined); +const saveMappings = jest.fn().mockReturnValue(undefined); +const forceSaveMappings = jest.fn().mockReturnValue(undefined); describe('When semantic_text is enabled', () => { const setup = (defaultProps: Partial) => @@ -124,7 +125,8 @@ describe('When semantic_text is enabled', () => { mappingsContextMocked.useMappingsState.mockReturnValue(defaultState); const { exists } = setup({ errorsInTrainedModelDeployment: {}, - fetchData, + saveMappings, + forceSaveMappings, setErrorsInTrainedModelDeployment: () => undefined, }); @@ -156,7 +158,8 @@ describe('When semantic_text is enabled', () => { } as any); const { exists, find } = setup({ errorsInTrainedModelDeployment: {}, - fetchData, + forceSaveMappings, + saveMappings, setErrorsInTrainedModelDeployment, }); @@ -170,11 +173,25 @@ describe('When semantic_text is enabled', () => { ); }); - it('should call fetch data if refresh button is pressed', async () => { + it('should call saveMappings if refresh button is pressed', async () => { await act(async () => { - find('confirmModalConfirmButton').simulate('click'); + find('tryAgainModalButton').simulate('click'); }); - expect(fetchData.mock.calls).toHaveLength(1); + expect(saveMappings.mock.calls).toHaveLength(1); + }); + it('should disable the force save mappings button if checkbox is not checked', async () => { + expect(find('forceSaveMappingsButton').props().disabled).toBe(true); + }); + it('checking checkbox should enable force save mappings button', async () => { + find('allowForceSaveMappingsCheckbox') + .simulate('change', { target: { checked: true } }) + .update(); + expect(find('forceSaveMappingsButton').props().disabled).toBe(false); + await act(async () => { + find('forceSaveMappingsButton').simulate('click'); + }); + + expect(forceSaveMappings.mock.calls).toHaveLength(1); }); }); @@ -200,8 +217,9 @@ describe('When semantic_text is enabled', () => { }, } as any); const { find } = setup({ - fetchData, errorsInTrainedModelDeployment: { '.elser_model_2': 'Error' }, + saveMappings, + forceSaveMappings, setErrorsInTrainedModelDeployment, }); @@ -216,15 +234,9 @@ describe('When semantic_text is enabled', () => { it("should call refresh method if 'Try again' button is pressed", async () => { await act(async () => { - find('confirmModalConfirmButton').simulate('click'); - }); - expect(fetchData.mock.calls).toHaveLength(1); - }); - - it('should call setIsVisibleForErrorModal method if cancel button is pressed', async () => { - await act(async () => { - find('confirmModalCancelButton').simulate('click'); + find('tryAgainModalButton').simulate('click'); }); + expect(saveMappings.mock.calls).toHaveLength(1); }); }); }); diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/type_parameter.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/type_parameter.tsx index 07a3bbb449694..0016707967396 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/type_parameter.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/type_parameter.tsx @@ -30,7 +30,7 @@ export const TypeParameter = ({ isMultiField, isRootLevelField, showDocLink = false, - isSemanticTextEnabled = false, + isSemanticTextEnabled = true, }: Props) => { const fieldTypeOptions = useMemo(() => { let options = isMultiField diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/utils.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/utils.ts index ed966805c0f2e..972c56677398f 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/utils.ts +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/utils.ts @@ -8,6 +8,8 @@ import { v4 as uuidv4 } from 'uuid'; import { cloneDeep } from 'lodash'; +import { InferenceServiceSettings } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { LocalInferenceServiceSettings } from '@kbn/ml-trained-models-utils/src/constants/trained_models'; import { ChildFieldName, ComboBoxOption, @@ -730,6 +732,16 @@ export function getStateWithCopyToFields(state: State): State { : [field.path.join('.')], }, }; + // add existing text field and children to byId list + const children = existingTextField.childFields + ? existingTextField.childFields.reduce>( + (acc, childFieldId) => { + acc[childFieldId] = state.mappingViewFields.byId[childFieldId]; + return acc; + }, + {} + ) + : {}; updatedState = { ...updatedState, fields: { @@ -737,6 +749,7 @@ export function getStateWithCopyToFields(state: State): State { byId: { ...updatedState.fields.byId, [existingTextField.id]: updatedTextField, + ...children, }, }, }; @@ -772,3 +785,9 @@ export function getStateWithCopyToFields(state: State): State { export const getFieldByPathName = (fields: NormalizedFields, name: string) => { return Object.values(fields.byId).find((field) => field.path.join('.') === name); }; + +export function isLocalModel( + model: InferenceServiceSettings +): model is LocalInferenceServiceSettings { + return Boolean((model as LocalInferenceServiceSettings).service_settings.model_id); +} diff --git a/x-pack/plugins/index_management/public/application/hooks/use_index_errors.ts b/x-pack/plugins/index_management/public/application/hooks/use_index_errors.ts new file mode 100644 index 0000000000000..f6c7767b4e2d0 --- /dev/null +++ b/x-pack/plugins/index_management/public/application/hooks/use_index_errors.ts @@ -0,0 +1,90 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import { Index } from '@kbn/index-management'; +import { MlPluginStart } from '@kbn/ml-plugin/public'; +import { useState, useEffect } from 'react'; +import { normalize } from '../components/mappings_editor/lib'; +import { isLocalModel } from '../components/mappings_editor/lib/utils'; +import { NormalizedField } from '../components/mappings_editor/types'; +import { useLoadIndexMappings, useLoadInferenceEndpoints } from '../services'; +import { parseMappings } from '../shared/parse_mappings'; + +export const useIndexErrors = ( + index: Index, + ml: MlPluginStart | undefined, + canGetTrainedModels: boolean +) => { + const { data } = useLoadIndexMappings(index.name); + const { data: endpoints } = useLoadInferenceEndpoints(); + const [errors, setErrors] = useState>([]); + useEffect(() => { + const mappings = data; + if (!mappings || !canGetTrainedModels || !endpoints || !ml) { + return; + } + + const parsedMappings = parseMappings(mappings); + const normalizedFields = normalize(parsedMappings.parsedDefaultValue?.fields); + const semanticTextFields = Object.values(normalizedFields.byId).filter( + (field) => field.source.type === 'semantic_text' + ); + const fetchErrors = async () => { + const trainedModelStats = await ml.mlApi?.trainedModels.getTrainedModelStats(); + + const semanticTextFieldsWithErrors = semanticTextFields + .map((field) => { + const model = endpoints.find( + (endpoint) => endpoint.model_id === field.source.inference_id + ); + if (!model) { + return { + field, + error: i18n.translate('xpack.idxMgmt.indexOverview.indexErrors.missingModelError', { + defaultMessage: 'Model not found for inference endpoint {inferenceId}', + values: { + inferenceId: field.source.inference_id as string, + }, + }), + }; + } + if (isLocalModel(model)) { + const modelId = model.service_settings.model_id; + const modelStats = trainedModelStats?.trained_model_stats.find( + (value) => value.model_id === modelId + ); + if (!modelStats || modelStats.deployment_stats?.state !== 'started') { + return { + field, + error: i18n.translate( + 'xpack.idxMgmt.indexOverview.indexErrors.modelNotStartedError', + { + defaultMessage: + 'Model {modelId} for inference endpoint {inferenceId} in field {fieldName} has not been started', + values: { + inferenceId: field.source.inference_id as string, + fieldName: field.path.join('.'), + modelId, + }, + } + ), + }; + } + } + return { field, error: '' }; + }) + .filter((value) => !!value.error); + setErrors(semanticTextFieldsWithErrors); + }; + + if (semanticTextFields.length) { + fetchErrors(); + } + }, [data, canGetTrainedModels, endpoints, ml, ml?.mlApi?.trainedModels]); + return errors; +}; diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_content.tsx b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_content.tsx index 015cfaaccdaa5..6860f9b832c74 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_content.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_content.tsx @@ -18,6 +18,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { RouteComponentProps } from 'react-router-dom'; +import { useIndexErrors } from '../../../../hooks/use_index_errors'; import { resetIndexUrlParams } from './reset_index_url_params'; import { renderBadges } from '../../../../lib/render_badges'; import { Index } from '../../../../../../common'; @@ -36,6 +37,7 @@ import { DetailsPageMappings } from './details_page_mappings'; import { DetailsPageSettings } from './details_page_settings'; import { DetailsPageStats } from './details_page_stats'; import { DetailsPageTab } from './details_page_tab'; +import { IndexErrorCallout } from './index_error_callout'; const defaultTabs: IndexDetailsTab[] = [ { @@ -92,10 +94,16 @@ export const DetailsPageContent: FunctionComponent = ({ navigateToIndicesList, }) => { const { + core: { + application: { capabilities }, + }, config: { enableIndexStats }, - plugins: { console: consolePlugin }, + plugins: { console: consolePlugin, ml }, services: { extensionsService }, } = useAppContext(); + const hasMLPermissions = capabilities?.ml?.canGetTrainedModels ? true : false; + + const indexErrors = useIndexErrors(index, ml, hasMLPermissions); const tabs = useMemo(() => { const sortedTabs = [...defaultTabs]; @@ -171,7 +179,9 @@ export const DetailsPageContent: FunctionComponent = ({ }} responsive="reverse" tabs={headerTabs} - /> + > + {indexErrors.length > 0 ? : null} +
(false); + const [isUpdatingMappings, setIsUpdatingMappings] = useState(false); useMappingsStateListener({ value: parsedDefaultValue, status: 'disabled' }); const { fetchInferenceToModelIdMap } = useDetailsPageMappingsModelManagement(); @@ -211,64 +212,55 @@ export const DetailsPageMappingsContent: FunctionComponent<{ fetchData(); // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - const fetchInferenceData = useCallback(async () => { - try { - if (!isSemanticTextEnabled) { - return; - } - - if (!hasMLPermissions) { - return; - } - - await fetchInferenceToModelIdMap(); - } catch (exception) { - setSaveMappingError(exception.message); - } - }, [fetchInferenceToModelIdMap, isSemanticTextEnabled, hasMLPermissions]); - - const updateMappings = useCallback(async () => { - const hasSemanticText = hasSemanticTextField(state.fields); - try { - if (isSemanticTextEnabled && hasMLPermissions && hasSemanticText) { - await fetchInferenceToModelIdMap(); - } - - const fields = hasSemanticText ? getStateWithCopyToFields(state).fields : state.fields; - - const denormalizedFields = deNormalize(fields); - - const inferenceIdsInPendingList = Object.values(deNormalize(fields)) - .filter(isSemanticTextField) - .map((field) => field.inference_id) - .filter( - (inferenceId: string) => - state.inferenceToModelIdMap?.[inferenceId] && - !state.inferenceToModelIdMap?.[inferenceId].isDeployed - ); - setHasSavedFields(true); - if (inferenceIdsInPendingList.length === 0) { - const { error } = await updateIndexMappings(indexName, denormalizedFields); - - if (!error) { - notificationService.showSuccessToast( - i18n.translate('xpack.idxMgmt.indexDetails.mappings.successfullyUpdatedIndexMappings', { - defaultMessage: 'Updated index mapping', - }) - ); - refetchMapping(); - setHasSavedFields(false); - } else { - setSaveMappingError(error.message); + }, [isSemanticTextEnabled, hasMLPermissions]); + + const updateMappings = useCallback( + async (forceSaveMappings?: boolean) => { + const hasSemanticText = hasSemanticTextField(state.fields); + setIsUpdatingMappings(true); + try { + if (isSemanticTextEnabled && hasMLPermissions && hasSemanticText && !forceSaveMappings) { + await fetchInferenceToModelIdMap(); + } + const fields = hasSemanticText ? getStateWithCopyToFields(state).fields : state.fields; + const denormalizedFields = deNormalize(fields); + const inferenceIdsInPendingList = forceSaveMappings + ? [] + : Object.values(denormalizedFields) + .filter(isSemanticTextField) + .map((field) => field.inference_id) + .filter( + (inferenceId: string) => + state.inferenceToModelIdMap?.[inferenceId] && + !state.inferenceToModelIdMap?.[inferenceId].isDeployed + ); + setHasSavedFields(true); + if (inferenceIdsInPendingList.length === 0) { + const { error } = await updateIndexMappings(indexName, denormalizedFields); + + if (!error) { + notificationService.showSuccessToast( + i18n.translate( + 'xpack.idxMgmt.indexDetails.mappings.successfullyUpdatedIndexMappings', + { + defaultMessage: 'Updated index mapping', + } + ) + ); + refetchMapping(); + setHasSavedFields(false); + } else { + setSaveMappingError(error.message); + } } + } catch (exception) { + setSaveMappingError(exception.message); } - } catch (exception) { - setSaveMappingError(exception.message); - } + setIsUpdatingMappings(false); + }, // eslint-disable-next-line react-hooks/exhaustive-deps - }, [state.fields]); + [state.fields] + ); const onSearchChange = useCallback( (value: string) => { @@ -496,7 +488,7 @@ export const DetailsPageMappingsContent: FunctionComponent<{ ) : ( updateMappings()} color="success" fill disabled={newFieldsLength === 0} @@ -613,8 +605,10 @@ export const DetailsPageMappingsContent: FunctionComponent<{ {isSemanticTextEnabled && isAddingFields && hasSavedFields && ( updateMappings(true)} + saveMappings={() => updateMappings()} + saveMappingsLoading={isUpdatingMappings} setErrorsInTrainedModelDeployment={setErrorsInTrainedModelDeployment} /> )} diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/index_error_callout.tsx b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/index_error_callout.tsx new file mode 100644 index 0000000000000..cb47339b39e98 --- /dev/null +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/index_error_callout.tsx @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useState } from 'react'; +import { EuiButton, EuiCallOut } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { NormalizedField } from '../../../../components/mappings_editor/types'; + +interface IndexErrorCalloutProps { + errors: Array<{ + field: NormalizedField; + error: string; + }>; +} + +export const IndexErrorCallout = ({ errors }: IndexErrorCalloutProps) => { + const [showErrors, setShowErrors] = useState(false); + return ( + + {showErrors && ( + <> +

+ {i18n.translate('xpack.idxMgmt.indexOverview.indexErrors.body', { + defaultMessage: 'Found errors in the following fields:', + })} + {errors.map(({ field, error }) => ( +

  • + {field.path.join('.')}: {error} +
  • + ))} +

    + setShowErrors(false)}> + {i18n.translate('xpack.idxMgmt.indexOverview.indexErrors.hideErrorsLabel', { + defaultMessage: 'Hide full error', + })} + + + )} + {!showErrors && ( + setShowErrors(true)}> + {i18n.translate('xpack.idxMgmt.indexOverview.indexErrors.showErrorsLabel', { + defaultMessage: 'Show full error', + })} + + )} +
    + ); +}; diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/trained_models_deployment_modal.tsx b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/trained_models_deployment_modal.tsx index 4bba408197661..6472b1d384e0c 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/trained_models_deployment_modal.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/trained_models_deployment_modal.tsx @@ -4,7 +4,23 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { EuiConfirmModal, useGeneratedHtmlId, EuiHealth } from '@elastic/eui'; +import { + EuiHealth, + EuiButton, + EuiCallOut, + EuiFlexGroup, + EuiFlexItem, + EuiSpacer, + EuiCheckbox, + EuiButtonEmpty, + EuiModal, + EuiModalHeader, + EuiModalHeaderTitle, + useGeneratedHtmlId, + EuiModalBody, + EuiModalFooter, + EuiBadge, +} from '@elastic/eui'; import React from 'react'; import { EuiLink } from '@elastic/eui'; @@ -17,8 +33,10 @@ import { useMappingsState } from '../../../../components/mappings_editor/mapping import { useAppContext } from '../../../../app_context'; export interface TrainedModelsDeploymentModalProps { - fetchData: () => void; errorsInTrainedModelDeployment: Record; + forceSaveMappings: () => void; + saveMappings: () => void; + saveMappingsLoading: boolean; setErrorsInTrainedModelDeployment: React.Dispatch< React.SetStateAction> >; @@ -29,18 +47,21 @@ const TRAINED_MODELS_MANAGE = 'trained_models'; export function TrainedModelsDeploymentModal({ errorsInTrainedModelDeployment = {}, - fetchData, + forceSaveMappings, + saveMappings, + saveMappingsLoading, setErrorsInTrainedModelDeployment, }: TrainedModelsDeploymentModalProps) { + const modalTitleId = useGeneratedHtmlId(); const { fields, inferenceToModelIdMap } = useMappingsState(); const { plugins: { ml }, url, } = useAppContext(); - const modalTitleId = useGeneratedHtmlId(); const [isModalVisible, setIsModalVisible] = useState(false); const closeModal = () => setIsModalVisible(false); const [mlManagementPageUrl, setMlManagementPageUrl] = useState(''); + const [allowForceSaveMappings, setAllowForceSaveMappings] = useState(false); const { showErrorToasts } = useMLModelNotificationToasts(); useEffect(() => { @@ -109,74 +130,143 @@ export function TrainedModelsDeploymentModal({ } }, [erroredDeployments.length, pendingDeployments.length]); return isModalVisible ? ( - 0 - ? i18n.translate( - 'xpack.idxMgmt.indexDetails.trainedModelsDeploymentModal.deploymentErrorTitle', - { - defaultMessage: 'Models could not be deployed', - } - ) - : i18n.translate('xpack.idxMgmt.indexDetails.trainedModelsDeploymentModal.titleLabel', { - defaultMessage: 'Models still deploying', - }) - } - titleProps={{ id: modalTitleId }} - onCancel={closeModal} - onConfirm={fetchData} - cancelButtonText={i18n.translate( - 'xpack.idxMgmt.indexDetails.trainedModelsDeploymentModal.closeButtonLabel', - { - defaultMessage: 'Close', - } - )} - confirmButtonText={i18n.translate( - 'xpack.idxMgmt.indexDetails.trainedModelsDeploymentModal.refreshButtonLabel', - { - defaultMessage: 'Refresh', - } - )} - defaultFocusedButton="confirm" + aria-labelledby={modalTitleId} + onClose={closeModal} data-test-subj="trainedModelsDeploymentModal" + initialFocus="[data-test-subj=tryAgainModalButton]" > -

    - {erroredDeployments.length > 0 - ? i18n.translate( - 'xpack.idxMgmt.indexDetails.trainedModelsDeploymentModal.deploymentErrorText', - { - defaultMessage: 'There was an error when trying to deploy the following models.', - } + + + {erroredDeployments.length > 0 + ? i18n.translate( + 'xpack.idxMgmt.indexDetails.trainedModelsDeploymentModal.deploymentErrorTitle', + { + defaultMessage: 'Models could not be deployed', + } + ) + : i18n.translate('xpack.idxMgmt.indexDetails.trainedModelsDeploymentModal.titleLabel', { + defaultMessage: 'Models still deploying', + })} + + + +

    + {erroredDeployments.length > 0 + ? i18n.translate( + 'xpack.idxMgmt.indexDetails.trainedModelsDeploymentModal.deploymentErrorText', + { + defaultMessage: 'There was an error when trying to deploy the following models.', + } + ) + : i18n.translate( + 'xpack.idxMgmt.indexDetails.trainedModelsDeploymentModal.textAboutDeploymentsNotCompleted', + { + defaultMessage: + 'Some fields are referencing models that have not yet completed deployment. Deployment may take a few minutes to complete.', + } + )} +

    + + + {i18n.translate( + 'xpack.idxMgmt.indexDetails.trainedModelsDeploymentModal.textTrainedModelManagementLink', + { + defaultMessage: 'Go to Trained Model Management', + } + )} + + +
      + {(erroredDeployments.length > 0 ? erroredDeployments : pendingDeployments).map( + (deployment) => ( +
    • + + {deployment} + +
    • ) - : i18n.translate( - 'xpack.idxMgmt.indexDetails.trainedModelsDeploymentModal.textAboutDeploymentsNotCompleted', + )} +
    + + + {i18n.translate( + 'xpack.idxMgmt.indexDetails.trainedModelsDeploymentModal.forceSaveMappingsDescription', + { + defaultMessage: + 'Saving a semantic text field referencing a model that is not running will break ingesting documents and searching over documents using or referencing that field.', + } + )} + + + setAllowForceSaveMappings(!allowForceSaveMappings)} + label={i18n.translate( + 'xpack.idxMgmt.indexDetails.trainedModelsDeploymentModal.allowForceSaveMappingsLabel', { - defaultMessage: - 'Some fields are referencing models that have not yet completed deployment. Deployment may take a few minutes to complete.', + defaultMessage: 'Allow semantic text mapping updates without a deployed model', } )} -

    -
      - {(erroredDeployments.length > 0 ? erroredDeployments : pendingDeployments).map( - (deployment) => ( -
    • - - {deployment} - -
    • - ) - )} -
    - - {i18n.translate( - 'xpack.idxMgmt.indexDetails.trainedModelsDeploymentModal.textTrainedModelManagementLink', - { - defaultMessage: 'Go to Trained Model Management', - } - )} - -
    + /> + + + + + + + {i18n.translate( + 'xpack.idxMgmt.indexDetails.trainedModelsDeploymentModal.cancelButtonLabel', + { + defaultMessage: 'Cancel', + } + )} + + + + + {i18n.translate( + 'xpack.idxMgmt.indexDetails.trainedModelsDeploymentModal.tryAgainButtonLabel', + { + defaultMessage: 'Try again', + } + )} + + + + + {i18n.translate( + 'xpack.idxMgmt.indexDetails.trainedModelsDeploymentModal.forceSaveMappingsLabel', + { + defaultMessage: 'Force save mappings', + } + )} + + + + + ) : null; } diff --git a/x-pack/plugins/index_management/public/application/services/api.ts b/x-pack/plugins/index_management/public/application/services/api.ts index e68335b8e0ba5..f182ffe53ce07 100644 --- a/x-pack/plugins/index_management/public/application/services/api.ts +++ b/x-pack/plugins/index_management/public/application/services/api.ts @@ -9,6 +9,7 @@ import { METRIC_TYPE } from '@kbn/analytics'; import type { SerializedEnrichPolicy } from '@kbn/index-management'; import { IndicesStatsResponse } from '@elastic/elasticsearch/lib/api/types'; import { InferenceAPIConfigResponse } from '@kbn/ml-trained-models-utils'; +import { MappingTypeMapping } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { API_BASE_PATH, INTERNAL_API_BASE_PATH, @@ -254,7 +255,7 @@ export async function loadIndexStats(indexName: string) { } export async function loadIndexMapping(indexName: string) { - const response = await httpService.httpClient.get( + const response = await httpService.httpClient.get( `${API_BASE_PATH}/mapping/${encodeURIComponent(indexName)}` ); return response; @@ -405,7 +406,7 @@ export function loadIndex(indexName: string) { } export function useLoadIndexMappings(indexName: string) { - return useRequest({ + return useRequest({ path: `${API_BASE_PATH}/mapping/${encodeURIComponent(indexName)}`, method: 'get', }); diff --git a/x-pack/plugins/index_management/public/hooks/use_details_page_mappings_model_management.ts b/x-pack/plugins/index_management/public/hooks/use_details_page_mappings_model_management.ts index 2d920a2d18ee0..e4cc3fa31dc10 100644 --- a/x-pack/plugins/index_management/public/hooks/use_details_page_mappings_model_management.ts +++ b/x-pack/plugins/index_management/public/hooks/use_details_page_mappings_model_management.ts @@ -10,8 +10,6 @@ import { ModelDownloadState, TrainedModelStat } from '@kbn/ml-plugin/common/type import { InferenceAPIConfigResponse } from '@kbn/ml-trained-models-utils'; import { LATEST_ELSER_VERSION, - InferenceServiceSettings, - LocalInferenceServiceSettings, LATEST_ELSER_MODEL_ID, LATEST_E5_MODEL_ID, ElserVersion, @@ -19,14 +17,11 @@ import { import { useCallback } from 'react'; import { AppDependencies, useAppContext } from '../application/app_context'; import { InferenceToModelIdMap } from '../application/components/mappings_editor/components/document_fields/fields'; +import { isLocalModel } from '../application/components/mappings_editor/lib/utils'; import { useDispatch } from '../application/components/mappings_editor/mappings_state_context'; import { DefaultInferenceModels } from '../application/components/mappings_editor/types'; import { getInferenceEndpoints } from '../application/services/api'; -function isLocalModel(model: InferenceServiceSettings): model is LocalInferenceServiceSettings { - return Boolean((model as LocalInferenceServiceSettings).service_settings.model_id); -} - const getCustomInferenceIdMap = ( models: InferenceAPIConfigResponse[], modelStatsById: Record, diff --git a/x-pack/plugins/index_management/server/types.ts b/x-pack/plugins/index_management/server/types.ts index 65f55b9f135fd..99ad3aec5b84b 100644 --- a/x-pack/plugins/index_management/server/types.ts +++ b/x-pack/plugins/index_management/server/types.ts @@ -7,7 +7,7 @@ import { IRouter } from '@kbn/core/server'; -import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { LicensingPluginSetup } from '@kbn/licensing-plugin/server'; import { SecurityPluginSetup } from '@kbn/security-plugin/server'; import { IndexDataEnricher } from './services'; diff --git a/x-pack/plugins/ingest_pipelines/server/types.ts b/x-pack/plugins/ingest_pipelines/server/types.ts index ea94ea5204e1e..34c821b90e79c 100644 --- a/x-pack/plugins/ingest_pipelines/server/types.ts +++ b/x-pack/plugins/ingest_pipelines/server/types.ts @@ -7,7 +7,7 @@ import { IRouter } from '@kbn/core/server'; import { SecurityPluginSetup } from '@kbn/security-plugin/server'; -import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { handleEsError } from './shared_imports'; export interface Dependencies { diff --git a/x-pack/plugins/integration_assistant/public/common/components/section_wrapper.tsx b/x-pack/plugins/integration_assistant/public/common/components/section_wrapper.tsx index 096998716fe2e..71df972f456a4 100644 --- a/x-pack/plugins/integration_assistant/public/common/components/section_wrapper.tsx +++ b/x-pack/plugins/integration_assistant/public/common/components/section_wrapper.tsx @@ -26,7 +26,7 @@ export const SectionWrapper = React.memo(({ children, title - +

    {title}

    diff --git a/x-pack/plugins/integration_assistant/public/common/lib/api.ts b/x-pack/plugins/integration_assistant/public/common/lib/api.ts index ab56578c8ce64..68c93f4f51a33 100644 --- a/x-pack/plugins/integration_assistant/public/common/lib/api.ts +++ b/x-pack/plugins/integration_assistant/public/common/lib/api.ts @@ -112,5 +112,6 @@ export const getInstalledPackages = async ({ }: RequestDeps): Promise => http.get(FLEET_PACKAGES_PATH, { headers: fleetDefaultHeaders, + query: { prerelease: true }, signal: abortSignal, }); diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/header/steps.tsx b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/header/steps.tsx index ae04d1d4b0089..76214e6c9f884 100644 --- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/header/steps.tsx +++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/header/steps.tsx @@ -6,9 +6,16 @@ */ import { EuiStepsHorizontal, type EuiStepStatus, type EuiStepsHorizontalProps } from '@elastic/eui'; +import { css } from '@emotion/react'; import { i18n } from '@kbn/i18n'; import React, { useMemo } from 'react'; +// Custom styles for the EuiStepsHorizontal component suggested by design team +const stepsCss = css` + margin-left: -66px; + margin-right: -59px; +`; + interface StepsProps { currentStep: number; setStep: (step: number) => void; @@ -74,6 +81,6 @@ export const Steps = React.memo(({ currentStep, setStep, isGeneratin ]; }, [currentStep, setStep, isGenerating]); - return ; + return ; }); Steps.displayName = 'Steps'; diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/mocks/state.ts b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/mocks/state.ts index 29f574776e295..3b356c39dea7f 100644 --- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/mocks/state.ts +++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/mocks/state.ts @@ -418,7 +418,7 @@ export const mockState: State = { dataStreamTitle: 'Mocked Data Stream Title', dataStreamName: 'mocked_datastream_name', dataStreamDescription: 'Mocked Data Stream Description', - inputType: 'filestream', + inputTypes: ['filestream'], logsSampleParsed: rawSamples, }, isGenerating: false, diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/connector_step/connector_step.tsx b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/connector_step/connector_step.tsx index 58090aec1b6cc..e51619a38f14b 100644 --- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/connector_step/connector_step.tsx +++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/connector_step/connector_step.tsx @@ -7,7 +7,17 @@ import React, { useCallback, useEffect, useState } from 'react'; import { useLoadConnectors } from '@kbn/elastic-assistant'; -import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner, EuiPopover, EuiLink } from '@elastic/eui'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiLoadingSpinner, + EuiPopover, + EuiLink, + EuiSpacer, + EuiText, + EuiIcon, + useEuiTheme, +} from '@elastic/eui'; import { AuthorizationWrapper, MissingPrivilegesTooltip, @@ -30,6 +40,7 @@ interface ConnectorStepProps { connector: AIConnector | undefined; } export const ConnectorStep = React.memo(({ connector }) => { + const { euiTheme } = useEuiTheme(); const { http, notifications } = useKibana().services; const { setConnector } = useActions(); const [connectors, setConnectors] = useState(); @@ -83,6 +94,15 @@ export const ConnectorStep = React.memo(({ connector }) => { )}
    + + + + + + + {i18n.SUPPORTED_MODELS_INFO} + + ); }); @@ -114,24 +134,22 @@ const CreateConnectorPopover = React.memo(({ onConn return ( - {i18n.CREATE_CONNECTOR} - + + + {i18n.CREATE_CONNECTOR} + + } isOpen={isOpen} closePopover={closePopover} data-test-subj="createConnectorPopover" > - - - - - + ); }); diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/connector_step/translations.ts b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/connector_step/translations.ts index 4b6ab77fb9790..d26b13e0db7e2 100644 --- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/connector_step/translations.ts +++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/connector_step/translations.ts @@ -24,3 +24,11 @@ export const CREATE_CONNECTOR = i18n.translate( defaultMessage: 'Create new connector', } ); + +export const SUPPORTED_MODELS_INFO = i18n.translate( + 'xpack.integrationAssistant.steps.connector.supportedModelsInfo', + { + defaultMessage: + "Automatic Import currently supports Anthropic models via Elastic's connector for Amazon Bedrock. Support for additional LLMs will be introduced soon", + } +); diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/data_stream_step.test.tsx b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/data_stream_step.test.tsx index b71fa6c5cabf1..476c5b24cbf5f 100644 --- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/data_stream_step.test.tsx +++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/data_stream_step.test.tsx @@ -12,6 +12,22 @@ import { DataStreamStep } from './data_stream_step'; import { ActionsProvider } from '../../state'; import { mockActions, mockState } from '../../mocks/state'; +jest.mock('@elastic/eui', () => { + return { + ...jest.requireActual('@elastic/eui'), + // Mocking EuiComboBox, as it utilizes "react-virtualized" for rendering search suggestions, + // which does not produce a valid component wrapper + EuiComboBox: (props: { onChange: (options: unknown) => void; 'data-test-subj': string }) => ( + { + props.onChange([{ value: syntheticEvent.target.value }]); + }} + /> + ), + }; +}); + jest.mock('./generation_modal', () => ({ GenerationModal: jest.fn(() =>
    ), })); @@ -204,7 +220,7 @@ describe('DataStreamStep', () => { it('should call setIntegrationSettings', () => { expect(mockActions.setIntegrationSettings).toHaveBeenCalledWith({ - inputType: dataCollectionMethod, + inputTypes: [dataCollectionMethod], }); }); }); diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/data_stream_step.tsx b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/data_stream_step.tsx index fbaf315374e92..08b9cb24232be 100644 --- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/data_stream_step.tsx +++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/data_stream_step.tsx @@ -6,14 +6,15 @@ */ import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import type { EuiComboBoxOptionOption } from '@elastic/eui'; import { + EuiComboBox, EuiFieldText, EuiFlexGroup, EuiFlexItem, EuiForm, EuiFormRow, EuiPanel, - EuiSelect, } from '@elastic/eui'; import type { InputType } from '../../../../../../common'; import { useActions, type State } from '../../state'; @@ -25,21 +26,21 @@ import { GenerationModal } from './generation_modal'; import { useLoadPackageNames } from './use_load_package_names'; import * as i18n from './translations'; -export const InputTypeOptions: Array<{ value: InputType; text: string }> = [ - { value: 'aws_cloudwatch', text: 'AWS Cloudwatch' }, - { value: 'aws_s3', text: 'AWS S3' }, - { value: 'azure_blob_storage', text: 'Azure Blob Storage' }, - { value: 'azure_eventhub', text: 'Azure Event Hub' }, - { value: 'cel', text: 'Common Expression Language (CEL)' }, - { value: 'cloudfoundry', text: 'Cloud Foundry' }, - { value: 'filestream', text: 'File Stream' }, - { value: 'gcp_pubsub', text: 'GCP Pub/Sub' }, - { value: 'gcs', text: 'Google Cloud Storage' }, - { value: 'http_endpoint', text: 'HTTP Endpoint' }, - { value: 'journald', text: 'Journald' }, - { value: 'kafka', text: 'Kafka' }, - { value: 'tcp', text: 'TCP' }, - { value: 'udp', text: 'UDP' }, +export const InputTypeOptions: Array> = [ + { value: 'aws_cloudwatch', label: 'AWS Cloudwatch' }, + { value: 'aws_s3', label: 'AWS S3' }, + { value: 'azure_blob_storage', label: 'Azure Blob Storage' }, + { value: 'azure_eventhub', label: 'Azure Event Hub' }, + { value: 'cel', label: 'Common Expression Language (CEL)' }, + { value: 'cloudfoundry', label: 'Cloud Foundry' }, + { value: 'filestream', label: 'File Stream' }, + { value: 'gcp_pubsub', label: 'GCP Pub/Sub' }, + { value: 'gcs', label: 'Google Cloud Storage' }, + { value: 'http_endpoint', label: 'HTTP Endpoint' }, + { value: 'journald', label: 'Journald' }, + { value: 'kafka', label: 'Kafka' }, + { value: 'tcp', label: 'TCP' }, + { value: 'udp', label: 'UDP' }, ]; const isValidName = (name: string) => /^[a-z0-9_]+$/.test(name); @@ -96,8 +97,8 @@ export const DataStreamStep = React.memo( setIntegrationValues({ dataStreamTitle: e.target.value }), dataStreamDescription: (e: React.ChangeEvent) => setIntegrationValues({ dataStreamDescription: e.target.value }), - inputType: (e: React.ChangeEvent) => { - setIntegrationValues({ inputType: e.target.value as InputType }); + inputTypes: (options: EuiComboBoxOptionOption[]) => { + setIntegrationValues({ inputTypes: options.map((option) => option.value as InputType) }); }, }; }, [setIntegrationValues, setInvalidFields, packageNames]); @@ -135,6 +136,14 @@ export const DataStreamStep = React.memo( } }, [packageNames, name]); + const selectedInputTypeOptions = useMemo>>( + () => + InputTypeOptions.filter((inputType) => + integrationSettings?.inputTypes?.includes(inputType.value as InputType) + ), + [integrationSettings?.inputTypes] + ); + return ( @@ -205,12 +214,12 @@ export const DataStreamStep = React.memo( /> - diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/deploy_step/deploy_step.test.tsx b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/deploy_step/deploy_step.test.tsx index 703a381a96e3b..094d4bd37ad31 100644 --- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/deploy_step/deploy_step.test.tsx +++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/deploy_step/deploy_step.test.tsx @@ -30,7 +30,7 @@ const parameters: BuildIntegrationRequestBody = { title: integrationSettings.dataStreamTitle!, description: integrationSettings.dataStreamDescription!, name: integrationSettings.dataStreamName!, - inputTypes: [integrationSettings.inputType!], + inputTypes: integrationSettings.inputTypes!, rawSamples: integrationSettings.logsSampleParsed!, docs: results.docs!, pipeline: results.pipeline, @@ -105,7 +105,7 @@ describe('DeployStep', () => { integrationName, integrationDescription: integrationSettings.description, dataStreamName: integrationSettings.dataStreamName, - inputType: integrationSettings.inputType, + inputTypes: integrationSettings.inputTypes, model: expect.any(String), actionTypeId: connector.actionTypeId, provider: connector.apiProvider ?? 'unknown', @@ -172,7 +172,7 @@ describe('DeployStep', () => { integrationName: integrationSettings.name, integrationDescription: integrationSettings.description, dataStreamName: integrationSettings.dataStreamName, - inputType: integrationSettings.inputType, + inputTypes: integrationSettings.inputTypes, model: expect.any(String), actionTypeId: connector.actionTypeId, provider: connector.apiProvider ?? 'unknown', @@ -224,7 +224,7 @@ describe('DeployStep', () => { integrationName: integrationSettings.name, integrationDescription: integrationSettings.description, dataStreamName: integrationSettings.dataStreamName, - inputType: integrationSettings.inputType, + inputTypes: integrationSettings.inputTypes, model: expect.any(String), actionTypeId: connector.actionTypeId, provider: connector.apiProvider ?? 'unknown', diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/deploy_step/use_deploy_integration.ts b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/deploy_step/use_deploy_integration.ts index 1de53e160efb1..7e12cdad8f611 100644 --- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/deploy_step/use_deploy_integration.ts +++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/deploy_step/use_deploy_integration.ts @@ -57,7 +57,7 @@ export const useDeployIntegration = ({ title: integrationSettings.dataStreamTitle ?? '', description: integrationSettings.dataStreamDescription ?? '', name: integrationSettings.dataStreamName ?? '', - inputTypes: integrationSettings.inputType ? [integrationSettings.inputType] : [], + inputTypes: integrationSettings.inputTypes ?? [], rawSamples: integrationSettings.logsSampleParsed ?? [], docs: result.docs ?? [], pipeline: result.pipeline, diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/types.ts b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/types.ts index 9e0100f2e95d5..ec0ea443d37c7 100644 --- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/types.ts +++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/types.ts @@ -32,6 +32,6 @@ export interface IntegrationSettings { dataStreamTitle?: string; dataStreamDescription?: string; dataStreamName?: string; - inputType?: InputType; + inputTypes?: InputType[]; logsSampleParsed?: string[]; } diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_landing/integration_assistant_card.tsx b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_landing/integration_assistant_card.tsx index c616cf5233279..444cd06a5e44f 100644 --- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_landing/integration_assistant_card.tsx +++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_landing/integration_assistant_card.tsx @@ -58,7 +58,7 @@ export const IntegrationAssistantCard = React.memo(() => { diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/telemetry.tsx b/x-pack/plugins/integration_assistant/public/components/create_integration/telemetry.tsx index f596964deb6ba..54988e238bd4d 100644 --- a/x-pack/plugins/integration_assistant/public/components/create_integration/telemetry.tsx +++ b/x-pack/plugins/integration_assistant/public/components/create_integration/telemetry.tsx @@ -120,7 +120,7 @@ export const TelemetryContextProvider = React.memo>(({ chi integrationName, integrationDescription: integrationSettings?.description ?? 'unknown', dataStreamName: integrationSettings?.dataStreamName ?? 'unknown', - inputType: integrationSettings?.inputType ?? 'unknown', + inputTypes: integrationSettings?.inputTypes ?? ['unknown'], actionTypeId: connector.actionTypeId, model: getConnectorModel(connector), provider: connector.apiProvider ?? 'unknown', diff --git a/x-pack/plugins/integration_assistant/public/services/telemetry/events.ts b/x-pack/plugins/integration_assistant/public/services/telemetry/events.ts index 91d8abbf68dbd..4d2d24ff7a657 100644 --- a/x-pack/plugins/integration_assistant/public/services/telemetry/events.ts +++ b/x-pack/plugins/integration_assistant/public/services/telemetry/events.ts @@ -169,11 +169,14 @@ export const telemetryEventsSchemas: TelemetryEventsSchemas = { optional: false, }, }, - inputType: { - type: 'keyword', - _meta: { - description: 'The input type used for the integration', - optional: false, + inputTypes: { + type: 'array', + items: { + type: 'keyword', + _meta: { + description: 'The input type used for the integration', + optional: false, + }, }, }, actionTypeId: { diff --git a/x-pack/plugins/integration_assistant/public/services/telemetry/types.ts b/x-pack/plugins/integration_assistant/public/services/telemetry/types.ts index 98ba1c0792caa..2f674b5880514 100644 --- a/x-pack/plugins/integration_assistant/public/services/telemetry/types.ts +++ b/x-pack/plugins/integration_assistant/public/services/telemetry/types.ts @@ -49,7 +49,7 @@ interface IntegrationAssistantCompleteData { integrationName: string; integrationDescription: string; dataStreamName: string; - inputType: string; + inputTypes: string[]; actionTypeId: string; model: string; provider: string; diff --git a/x-pack/plugins/integration_assistant/server/integration_builder/build_integration.ts b/x-pack/plugins/integration_assistant/server/integration_builder/build_integration.ts index 9422b99b0ab29..18d0156a673f8 100644 --- a/x-pack/plugins/integration_assistant/server/integration_builder/build_integration.ts +++ b/x-pack/plugins/integration_assistant/server/integration_builder/build_integration.ts @@ -16,6 +16,8 @@ import { createDataStream } from './data_stream'; import { createFieldMapping } from './fields'; import { createPipeline } from './pipeline'; +const initialVersion = '1.0.0'; + export async function buildPackage(integration: Integration): Promise { const templateDir = joinPath(__dirname, '../templates'); const agentTemplates = joinPath(templateDir, 'agent'); @@ -26,7 +28,7 @@ export async function buildPackage(integration: Integration): Promise { }); const tmpDir = joinPath(tmpdir(), `integration-assistant-${generateUniqueId()}`); - const packageDirectoryName = `${integration.name}-0.1.0`; + const packageDirectoryName = `${integration.name}-${initialVersion}`; const packageDir = createDirectories(tmpDir, integration, packageDirectoryName); const dataStreamsDir = joinPath(packageDir, 'data_stream'); @@ -86,7 +88,7 @@ function createBuildFile(packageDir: string): void { function createChangelog(packageDir: string): void { const changelogTemplate = nunjucks.render('changelog.yml.njk', { - initial_version: '0.1.0', + initial_version: initialVersion, }); createSync(joinPath(packageDir, 'changelog.yml'), changelogTemplate); @@ -132,7 +134,7 @@ function createPackageManifest(packageDir: string, integration: Integration): vo format_version: '3.1.4', package_title: integration.title, package_name: integration.name, - package_version: '0.1.0', + package_version: initialVersion, package_description: integration.description, package_logo: integration.logo, package_owner: '@elastic/custom-integrations', diff --git a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/helpers.ts b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/helpers.ts index e0f6654287a3f..dcd47d6c9170c 100644 --- a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/helpers.ts +++ b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/helpers.ts @@ -34,12 +34,13 @@ export const getSuggestions = async ( const dataView = dataViewSpec ? await deps.dataViews.create(dataViewSpec) - : await getESQLAdHocDataview(indexPattern, deps.dataViews); + : await getESQLAdHocDataview(query.esql, deps.dataViews); const columns = await getESQLQueryColumns({ esqlQuery: 'esql' in query ? query.esql : '', search: deps.data.search.search, signal: abortController?.signal, + timeRange: deps.data.query.timefilter.timefilter.getAbsoluteTime(), }); const context = { dataViewSpec: dataView?.toSpec(false), diff --git a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.tsx b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.tsx index 98233c7ebffef..f796ea26810c8 100644 --- a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.tsx +++ b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.tsx @@ -453,7 +453,7 @@ export function LensEditConfigurationFlyout({ }} expandCodeEditor={(status: boolean) => {}} isCodeEditorExpanded - detectTimestamp={Boolean(adHocDataViews?.[0]?.timeFieldName)} + detectedTimestamp={adHocDataViews?.[0]?.timeFieldName} hideTimeFilterInfo={hideTimeFilterInfo} errors={errors} warning={ diff --git a/x-pack/plugins/lens/public/datasources/text_based/utils.test.ts b/x-pack/plugins/lens/public/datasources/text_based/utils.test.ts index 4551db5952fa7..a93cd76e59f39 100644 --- a/x-pack/plugins/lens/public/datasources/text_based/utils.test.ts +++ b/x-pack/plugins/lens/public/datasources/text_based/utils.test.ts @@ -247,7 +247,7 @@ describe('Text based languages utils', () => { }, { id: '4', - timeField: 'timeField', + timeField: undefined, title: 'my-adhoc-index-pattern', }, ], @@ -259,7 +259,111 @@ describe('Text based languages utils', () => { query: { esql: 'FROM my-fake-index-pattern', }, + timeField: undefined, + }, + }, + }); + }); + + it('should return the correct state for query with named params', async () => { + const state = { + layers: { + first: { + columns: [], + query: undefined, + index: '', + }, + }, + indexPatternRefs: [], + initialContext: { + textBasedColumns: textBasedQueryColumns, + query: { esql: 'from foo' }, + fieldName: '', + dataViewSpec: { + title: 'foo', + id: '1', + name: 'Foo', + }, + }, + }; + const dataViewsMock = dataViewPluginMocks.createStartContract(); + const dataMock = dataPluginMock.createStartContract(); + const expressionsMock = expressionsPluginMock.createStartContract(); + const updatedState = await getStateFromAggregateQuery( + state, + { esql: 'FROM my-fake-index-pattern | WHERE time <= ?latest' }, + { + ...dataViewsMock, + getIdsWithTitle: jest.fn().mockReturnValue( + Promise.resolve([ + { id: '1', title: 'my-fake-index-pattern' }, + { id: '2', title: 'my-fake-restricted-pattern' }, + { id: '3', title: 'my-compatible-pattern' }, + ]) + ), + get: jest.fn().mockReturnValue( + Promise.resolve({ + id: '1', + title: 'my-fake-index-pattern', + timeFieldName: 'timeField', + }) + ), + create: jest.fn().mockReturnValue( + Promise.resolve({ + id: '4', + title: 'my-adhoc-index-pattern', + name: 'my-adhoc-index-pattern', + timeFieldName: 'timeField', + isPersisted: () => false, + }) + ), + }, + dataMock, + expressionsMock + ); + + expect(updatedState).toStrictEqual({ + initialContext: { + textBasedColumns: textBasedQueryColumns, + query: { esql: 'from foo' }, + fieldName: '', + dataViewSpec: { + title: 'foo', + id: '1', + name: 'Foo', + }, + }, + indexPatternRefs: [ + { + id: '3', timeField: 'timeField', + title: 'my-compatible-pattern', + }, + { + id: '1', + timeField: 'timeField', + title: 'my-fake-index-pattern', + }, + { + id: '2', + timeField: 'timeField', + title: 'my-fake-restricted-pattern', + }, + { + id: '4', + timeField: 'time', + title: 'my-adhoc-index-pattern', + }, + ], + layers: { + first: { + columns: [], + errors: [], + index: '4', + query: { + esql: 'FROM my-fake-index-pattern | WHERE time <= ?latest', + }, + timeField: 'time', }, }, }); diff --git a/x-pack/plugins/lens/public/datasources/text_based/utils.ts b/x-pack/plugins/lens/public/datasources/text_based/utils.ts index 9621ab8103e4a..79e3a15e78a50 100644 --- a/x-pack/plugins/lens/public/datasources/text_based/utils.ts +++ b/x-pack/plugins/lens/public/datasources/text_based/utils.ts @@ -85,7 +85,7 @@ export async function getStateFromAggregateQuery( let columnsFromQuery: DatatableColumn[] = []; let timeFieldName; try { - const dataView = await getESQLAdHocDataview(indexPattern, dataViews); + const dataView = await getESQLAdHocDataview(query.esql, dataViews); if (dataView && dataView.id) { dataViewId = dataView?.id; diff --git a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/create_action_helpers.ts b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/create_action_helpers.ts index d11a32bbd5e06..65ac6ef69aee8 100644 --- a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/create_action_helpers.ts +++ b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/create_action_helpers.ts @@ -49,7 +49,7 @@ export async function executeCreateAction({ const getFallbackDataView = async () => { const indexName = await getIndexForESQLQuery({ dataViews: deps.dataViews }); if (!indexName) return null; - const dataView = await getESQLAdHocDataview(indexName, deps.dataViews); + const dataView = await getESQLAdHocDataview(`from ${indexName}`, deps.dataViews); return dataView; }; @@ -75,6 +75,7 @@ export async function executeCreateAction({ esqlQuery: `from ${defaultIndex}`, search: deps.data.search.search, signal: abortController.signal, + timeRange: deps.data.query.timefilter.timefilter.getAbsoluteTime(), }); const context = { diff --git a/x-pack/plugins/lens/public/visualizations/metric/toolbar/titles_and_text_popover.test.tsx b/x-pack/plugins/lens/public/visualizations/metric/toolbar/titles_and_text_popover.test.tsx index 6031d74fc8e37..bcb529131c0f7 100644 --- a/x-pack/plugins/lens/public/visualizations/metric/toolbar/titles_and_text_popover.test.tsx +++ b/x-pack/plugins/lens/public/visualizations/metric/toolbar/titles_and_text_popover.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { CustomPaletteParams, PaletteOutput } from '@kbn/coloring'; -import { fireEvent, render, screen, waitFor } from '@testing-library/react'; +import { fireEvent, render, screen } from '@testing-library/react'; import { MetricVisualizationState } from '../types'; import { TitlesAndTextPopover } from './titles_and_text_popover'; import { EuiButtonGroupTestHarness } from '@kbn/test-eui-helpers'; @@ -57,7 +57,17 @@ describe('TitlesAndTextPopover', () => { }; }; - afterEach(() => mockSetState.mockClear()); + beforeAll(() => { + jest.useFakeTimers(); + }); + + afterEach(() => { + mockSetState.mockClear(); + }); + + afterAll(() => { + jest.useRealTimers(); + }); it('should set a subtitle', async () => { renderToolbarOptions({ @@ -71,11 +81,14 @@ describe('TitlesAndTextPopover', () => { const subtitleField = screen.getByDisplayValue('subtitle'); // cannot use userEvent because the element cannot be clicked on fireEvent.change(subtitleField, { target: { value: newSubtitle + ' 1' } }); - await waitFor(() => expect(mockSetState).toHaveBeenCalled()); + jest.advanceTimersByTime(256); + expect(mockSetState).toHaveBeenCalled(); fireEvent.change(subtitleField, { target: { value: newSubtitle + ' 2' } }); - await waitFor(() => expect(mockSetState).toHaveBeenCalledTimes(2)); + jest.advanceTimersByTime(256); + expect(mockSetState).toHaveBeenCalledTimes(2); fireEvent.change(subtitleField, { target: { value: newSubtitle + ' 3' } }); - await waitFor(() => expect(mockSetState).toHaveBeenCalledTimes(3)); + jest.advanceTimersByTime(256); + expect(mockSetState).toHaveBeenCalledTimes(3); expect(mockSetState.mock.calls.map(([state]) => state.subtitle)).toMatchInlineSnapshot(` Array [ "new subtitle hey 1", diff --git a/x-pack/plugins/license_management/server/types.ts b/x-pack/plugins/license_management/server/types.ts index c888bb30c2265..4cc81a15adfbe 100644 --- a/x-pack/plugins/license_management/server/types.ts +++ b/x-pack/plugins/license_management/server/types.ts @@ -7,7 +7,7 @@ import { IScopedClusterClient, IRouter } from '@kbn/core/server'; -import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { LicensingPluginStart } from '@kbn/licensing-plugin/server'; import { SecurityPluginSetup } from '@kbn/security-plugin/server'; import { handleEsError } from './shared_imports'; diff --git a/x-pack/plugins/logstash/server/plugin.ts b/x-pack/plugins/logstash/server/plugin.ts index 24b8fa5a23b2d..597cf5eb0f2aa 100644 --- a/x-pack/plugins/logstash/server/plugin.ts +++ b/x-pack/plugins/logstash/server/plugin.ts @@ -7,7 +7,7 @@ import { CoreSetup, CoreStart, Logger, Plugin, PluginInitializerContext } from '@kbn/core/server'; import { LicensingPluginSetup } from '@kbn/licensing-plugin/server'; -import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { registerRoutes } from './routes'; interface SetupDeps { diff --git a/x-pack/plugins/maps/public/classes/sources/esql_source/create_source_editor.tsx b/x-pack/plugins/maps/public/classes/sources/esql_source/create_source_editor.tsx index f0f02f788a8b9..965841caeffeb 100644 --- a/x-pack/plugins/maps/public/classes/sources/esql_source/create_source_editor.tsx +++ b/x-pack/plugins/maps/public/classes/sources/esql_source/create_source_editor.tsx @@ -56,7 +56,10 @@ export function CreateSourceEditor(props: Props) { getDataView() .then(async (dataView) => { const adhocDataView = dataView - ? await getESQLAdHocDataview(dataView.getIndexPattern(), getIndexPatternService()) + ? await getESQLAdHocDataview( + `from ${dataView.getIndexPattern()}`, + getIndexPatternService() + ) : undefined; if (ignore) { return; diff --git a/x-pack/plugins/maps/public/classes/sources/esql_source/esql_source.tsx b/x-pack/plugins/maps/public/classes/sources/esql_source/esql_source.tsx index da689d12eaee5..fa69b4a4db046 100644 --- a/x-pack/plugins/maps/public/classes/sources/esql_source/esql_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/esql_source/esql_source.tsx @@ -11,7 +11,12 @@ import { lastValueFrom } from 'rxjs'; import { tap } from 'rxjs'; import { v4 as uuidv4 } from 'uuid'; import { Adapters } from '@kbn/inspector-plugin/common/adapters'; -import { getIndexPatternFromESQLQuery, getLimitFromESQLQuery } from '@kbn/esql-utils'; +import { + getIndexPatternFromESQLQuery, + getLimitFromESQLQuery, + getEarliestLatestParams, + hasEarliestLatestParams, +} from '@kbn/esql-utils'; import { buildEsQuery } from '@kbn/es-query'; import type { Filter, Query } from '@kbn/es-query'; import type { ESQLSearchParams, ESQLSearchResponse } from '@kbn/es-types'; @@ -112,11 +117,11 @@ export class ESQLSource } getApplyGlobalQuery() { - return this._descriptor.narrowByGlobalSearch; + return this._descriptor.narrowByGlobalSearch || hasEarliestLatestParams(this._descriptor.esql); } async isTimeAware() { - return this._descriptor.narrowByGlobalTime; + return this._descriptor.narrowByGlobalTime || hasEarliestLatestParams(this._descriptor.esql); } getApplyGlobalTime() { @@ -183,6 +188,14 @@ export class ESQLSource filters.push(extentFilter); } + const timeRange = requestMeta.timeslice + ? { + from: new Date(requestMeta.timeslice.from).toISOString(), + to: new Date(requestMeta.timeslice.to).toISOString(), + mode: 'absolute' as 'absolute', + } + : requestMeta.timeFilters; + if (requestMeta.applyGlobalTime) { if (!this._descriptor.dateField) { throw new Error( @@ -192,21 +205,20 @@ export class ESQLSource }) ); } - const timeRange = requestMeta.timeslice - ? { - from: new Date(requestMeta.timeslice.from).toISOString(), - to: new Date(requestMeta.timeslice.to).toISOString(), - mode: 'absolute' as 'absolute', - } - : requestMeta.timeFilters; const timeFilter = getTime(undefined, timeRange, { fieldName: this._descriptor.dateField, }); + if (timeFilter) { filters.push(timeFilter); } } + const namedParams = getEarliestLatestParams(this._descriptor.esql, timeRange); + if (namedParams.length) { + params.params = namedParams; + } + params.filter = buildEsQuery(undefined, query, filters, getEsQueryConfig(getUiSettings())); const requestResponder = inspectorAdapters.requests!.start( diff --git a/x-pack/plugins/maps/public/classes/sources/esql_source/esql_utils.ts b/x-pack/plugins/maps/public/classes/sources/esql_source/esql_utils.ts index 32ab2c88cc57b..9f082c6f70e3a 100644 --- a/x-pack/plugins/maps/public/classes/sources/esql_source/esql_utils.ts +++ b/x-pack/plugins/maps/public/classes/sources/esql_source/esql_utils.ts @@ -7,11 +7,7 @@ import { i18n } from '@kbn/i18n'; import type { DataView } from '@kbn/data-plugin/common'; -import { - getESQLAdHocDataview, - getIndexPatternFromESQLQuery, - getESQLQueryColumnsRaw, -} from '@kbn/esql-utils'; +import { getESQLAdHocDataview, getESQLQueryColumnsRaw } from '@kbn/esql-utils'; import type { ESQLColumn } from '@kbn/es-types'; import { ES_GEO_FIELD_TYPE } from '../../../../common/constants'; import { getData, getIndexPatternService } from '../../../kibana_services'; @@ -53,14 +49,12 @@ export function verifyGeometryColumn(columns: ESQLColumn[]) { } export async function getESQLMeta(esql: string) { - const adhocDataView = await getESQLAdHocDataview( - getIndexPatternFromESQLQuery(esql), - getIndexPatternService() - ); + const adhocDataView = await getESQLAdHocDataview(esql, getIndexPatternService()); return { columns: await getESQLQueryColumnsRaw({ esqlQuery: esql, search: getData().search.search, + timeRange: getData().query.timefilter.timefilter.getAbsoluteTime(), }), adhocDataViewId: adhocDataView.id!, ...getFields(adhocDataView), diff --git a/x-pack/plugins/maps/server/types.ts b/x-pack/plugins/maps/server/types.ts index 4e9c6af769645..53efae6f876be 100644 --- a/x-pack/plugins/maps/server/types.ts +++ b/x-pack/plugins/maps/server/types.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { PluginSetupContract as FeaturesPluginSetupContract } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server'; import { HomeServerPluginSetup } from '@kbn/home-plugin/server'; import { LicensingPluginSetup } from '@kbn/licensing-plugin/server'; @@ -20,7 +20,7 @@ import type { ContentManagementServerSetup } from '@kbn/content-management-plugi export interface SetupDeps { data: DataPluginSetup; - features: FeaturesPluginSetupContract; + features: FeaturesPluginSetup; usageCollection?: UsageCollectionSetup; home?: HomeServerPluginSetup; licensing: LicensingPluginSetup; diff --git a/x-pack/plugins/ml/server/types.ts b/x-pack/plugins/ml/server/types.ts index f303569f4ca24..261ebfd7e2369 100644 --- a/x-pack/plugins/ml/server/types.ts +++ b/x-pack/plugins/ml/server/types.ts @@ -9,7 +9,7 @@ import type { HomeServerPluginSetup } from '@kbn/home-plugin/server'; import type { IRouter } from '@kbn/core/server'; import type { CloudSetup } from '@kbn/cloud-plugin/server'; import type { SecurityPluginSetup } from '@kbn/security-plugin/server'; -import type { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import type { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import type { LicensingPluginSetup, LicensingPluginStart } from '@kbn/licensing-plugin/server'; import type { SpacesPluginSetup, SpacesPluginStart } from '@kbn/spaces-plugin/server'; diff --git a/x-pack/plugins/monitoring/server/types.ts b/x-pack/plugins/monitoring/server/types.ts index 7e056cbac5fb8..06c796764b5f7 100644 --- a/x-pack/plugins/monitoring/server/types.ts +++ b/x-pack/plugins/monitoring/server/types.ts @@ -31,7 +31,7 @@ import { import { InfraPluginSetup, InfraRequestHandlerContext } from '@kbn/infra-plugin/server'; import { PluginSetupContract as AlertingPluginSetup } from '@kbn/alerting-plugin/server'; import { LicensingPluginStart } from '@kbn/licensing-plugin/server'; -import { PluginSetupContract as FeaturesPluginSetupContract } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { EncryptedSavedObjectsPluginSetup } from '@kbn/encrypted-saved-objects-plugin/server'; import { CloudSetup } from '@kbn/cloud-plugin/server'; import { RouteConfig, RouteMethod, Headers } from '@kbn/core/server'; @@ -53,7 +53,7 @@ export interface MonitoringLicenseService { export interface PluginsSetup { encryptedSavedObjects?: EncryptedSavedObjectsPluginSetup; usageCollection?: UsageCollectionSetup; - features: FeaturesPluginSetupContract; + features: FeaturesPluginSetup; alerting?: AlertingPluginSetupContract; infra: InfraPluginSetup; cloud?: CloudSetup; diff --git a/x-pack/plugins/observability_solution/apm/common/agent_configuration/runtime_types/float_four_decimal_places_rt.test.ts b/x-pack/plugins/observability_solution/apm/common/agent_configuration/runtime_types/float_four_decimal_places_rt.test.ts new file mode 100644 index 0000000000000..1281368387d93 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/common/agent_configuration/runtime_types/float_four_decimal_places_rt.test.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 { floatFourDecimalPlacesRt } from './float_four_decimal_places_rt'; +import { isRight } from 'fp-ts/lib/Either'; + +describe('floatFourDecimalPlacesRt', () => { + it('does not accept empty values', () => { + expect(isRight(floatFourDecimalPlacesRt.decode(undefined))).toBe(false); + expect(isRight(floatFourDecimalPlacesRt.decode(null))).toBe(false); + expect(isRight(floatFourDecimalPlacesRt.decode(''))).toBe(false); + }); + + it('should only accept stringified numbers', () => { + expect(isRight(floatFourDecimalPlacesRt.decode('0.5'))).toBe(true); + expect(isRight(floatFourDecimalPlacesRt.decode(0.5))).toBe(false); + }); + + it('checks if the number falls within 0, 1', () => { + expect(isRight(floatFourDecimalPlacesRt.decode('0'))).toBe(true); + expect(isRight(floatFourDecimalPlacesRt.decode('0.5'))).toBe(true); + expect(isRight(floatFourDecimalPlacesRt.decode('-0.1'))).toBe(false); + expect(isRight(floatFourDecimalPlacesRt.decode('1.1'))).toBe(false); + expect(isRight(floatFourDecimalPlacesRt.decode(NaN))).toBe(false); + }); + + it('checks whether the number of decimals is 4', () => { + expect(isRight(floatFourDecimalPlacesRt.decode('1'))).toBe(true); + expect(isRight(floatFourDecimalPlacesRt.decode('0.9'))).toBe(true); + expect(isRight(floatFourDecimalPlacesRt.decode('0.99'))).toBe(true); + expect(isRight(floatFourDecimalPlacesRt.decode('0.999'))).toBe(true); + expect(isRight(floatFourDecimalPlacesRt.decode('0.9999'))).toBe(true); + expect(isRight(floatFourDecimalPlacesRt.decode('0.99999'))).toBe(false); + }); +}); diff --git a/x-pack/plugins/observability_solution/apm/common/agent_configuration/runtime_types/float_four_decimal_places_rt.ts b/x-pack/plugins/observability_solution/apm/common/agent_configuration/runtime_types/float_four_decimal_places_rt.ts new file mode 100644 index 0000000000000..681eb9322fe9d --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/common/agent_configuration/runtime_types/float_four_decimal_places_rt.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as t from 'io-ts'; +import { either } from 'fp-ts/lib/Either'; + +export const floatFourDecimalPlacesRt = new t.Type( + 'floatFourDecimalPlacesRt', + t.string.is, + (input, context) => { + return either.chain(t.string.validate(input, context), (inputAsString) => { + const inputAsFloat = parseFloat(inputAsString); + const maxFourDecimals = parseFloat(inputAsFloat.toFixed(4)) === inputAsFloat; + + const isValid = inputAsFloat >= 0 && inputAsFloat <= 1 && maxFourDecimals; + + return isValid + ? t.success(inputAsString) + : t.failure(input, context, 'Must be a number between 0.0000 and 1'); + }); + }, + t.identity +); diff --git a/x-pack/plugins/observability_solution/apm/common/agent_configuration/runtime_types/float_rt.test.ts b/x-pack/plugins/observability_solution/apm/common/agent_configuration/runtime_types/float_rt.test.ts deleted file mode 100644 index f766c7ca70d79..0000000000000 --- a/x-pack/plugins/observability_solution/apm/common/agent_configuration/runtime_types/float_rt.test.ts +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { floatRt } from './float_rt'; -import { isRight } from 'fp-ts/lib/Either'; - -describe('floatRt', () => { - it('does not accept empty values', () => { - expect(isRight(floatRt.decode(undefined))).toBe(false); - expect(isRight(floatRt.decode(null))).toBe(false); - expect(isRight(floatRt.decode(''))).toBe(false); - }); - - it('should only accept stringified numbers', () => { - expect(isRight(floatRt.decode('0.5'))).toBe(true); - expect(isRight(floatRt.decode(0.5))).toBe(false); - }); - - it('checks if the number falls within 0, 1', () => { - expect(isRight(floatRt.decode('0'))).toBe(true); - expect(isRight(floatRt.decode('0.5'))).toBe(true); - expect(isRight(floatRt.decode('-0.1'))).toBe(false); - expect(isRight(floatRt.decode('1.1'))).toBe(false); - expect(isRight(floatRt.decode(NaN))).toBe(false); - }); - - it('checks whether the number of decimals is 3', () => { - expect(isRight(floatRt.decode('1'))).toBe(true); - expect(isRight(floatRt.decode('0.9'))).toBe(true); - expect(isRight(floatRt.decode('0.99'))).toBe(true); - expect(isRight(floatRt.decode('0.999'))).toBe(true); - expect(isRight(floatRt.decode('0.9999'))).toBe(false); - }); -}); diff --git a/x-pack/plugins/observability_solution/apm/common/agent_configuration/runtime_types/float_three_decimal_places_rt.test.ts b/x-pack/plugins/observability_solution/apm/common/agent_configuration/runtime_types/float_three_decimal_places_rt.test.ts new file mode 100644 index 0000000000000..cbf6ba8a60d9a --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/common/agent_configuration/runtime_types/float_three_decimal_places_rt.test.ts @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { floatThreeDecimalPlacesRt } from './float_three_decimal_places_rt'; +import { isRight } from 'fp-ts/lib/Either'; + +describe('floatThreeDecimalPlacesRt', () => { + it('does not accept empty values', () => { + expect(isRight(floatThreeDecimalPlacesRt.decode(undefined))).toBe(false); + expect(isRight(floatThreeDecimalPlacesRt.decode(null))).toBe(false); + expect(isRight(floatThreeDecimalPlacesRt.decode(''))).toBe(false); + }); + + it('should only accept stringified numbers', () => { + expect(isRight(floatThreeDecimalPlacesRt.decode('0.5'))).toBe(true); + expect(isRight(floatThreeDecimalPlacesRt.decode(0.5))).toBe(false); + }); + + it('checks if the number falls within 0, 1', () => { + expect(isRight(floatThreeDecimalPlacesRt.decode('0'))).toBe(true); + expect(isRight(floatThreeDecimalPlacesRt.decode('0.5'))).toBe(true); + expect(isRight(floatThreeDecimalPlacesRt.decode('-0.1'))).toBe(false); + expect(isRight(floatThreeDecimalPlacesRt.decode('1.1'))).toBe(false); + expect(isRight(floatThreeDecimalPlacesRt.decode(NaN))).toBe(false); + }); + + it('checks whether the number of decimals is 3', () => { + expect(isRight(floatThreeDecimalPlacesRt.decode('1'))).toBe(true); + expect(isRight(floatThreeDecimalPlacesRt.decode('0.9'))).toBe(true); + expect(isRight(floatThreeDecimalPlacesRt.decode('0.99'))).toBe(true); + expect(isRight(floatThreeDecimalPlacesRt.decode('0.999'))).toBe(true); + expect(isRight(floatThreeDecimalPlacesRt.decode('0.9999'))).toBe(false); + }); +}); diff --git a/x-pack/plugins/observability_solution/apm/common/agent_configuration/runtime_types/float_rt.ts b/x-pack/plugins/observability_solution/apm/common/agent_configuration/runtime_types/float_three_decimal_places_rt.ts similarity index 88% rename from x-pack/plugins/observability_solution/apm/common/agent_configuration/runtime_types/float_rt.ts rename to x-pack/plugins/observability_solution/apm/common/agent_configuration/runtime_types/float_three_decimal_places_rt.ts index a0e2d3f5b60ba..9d7c3253f0d15 100644 --- a/x-pack/plugins/observability_solution/apm/common/agent_configuration/runtime_types/float_rt.ts +++ b/x-pack/plugins/observability_solution/apm/common/agent_configuration/runtime_types/float_three_decimal_places_rt.ts @@ -8,8 +8,8 @@ import * as t from 'io-ts'; import { either } from 'fp-ts/lib/Either'; -export const floatRt = new t.Type( - 'floatRt', +export const floatThreeDecimalPlacesRt = new t.Type( + 'floatThreeDecimalPlacesRt', t.string.is, (input, context) => { return either.chain(t.string.validate(input, context), (inputAsString) => { diff --git a/x-pack/plugins/observability_solution/apm/common/agent_configuration/setting_definitions/__snapshots__/index.test.ts.snap b/x-pack/plugins/observability_solution/apm/common/agent_configuration/setting_definitions/__snapshots__/index.test.ts.snap index e82a61cbd0cd1..54174700ba12c 100644 --- a/x-pack/plugins/observability_solution/apm/common/agent_configuration/setting_definitions/__snapshots__/index.test.ts.snap +++ b/x-pack/plugins/observability_solution/apm/common/agent_configuration/setting_definitions/__snapshots__/index.test.ts.snap @@ -258,7 +258,7 @@ Array [ Object { "key": "session_sample_rate", "type": "float", - "validationName": "floatRt", + "validationName": "floatThreeDecimalPlacesRt", }, Object { "key": "span_compression_enabled", @@ -341,22 +341,22 @@ Array [ Object { "key": "stress_monitor_gc_relief_threshold", "type": "float", - "validationName": "floatRt", + "validationName": "floatThreeDecimalPlacesRt", }, Object { "key": "stress_monitor_gc_stress_threshold", "type": "float", - "validationName": "floatRt", + "validationName": "floatThreeDecimalPlacesRt", }, Object { "key": "stress_monitor_system_cpu_relief_threshold", "type": "float", - "validationName": "floatRt", + "validationName": "floatThreeDecimalPlacesRt", }, Object { "key": "stress_monitor_system_cpu_stress_threshold", "type": "float", - "validationName": "floatRt", + "validationName": "floatThreeDecimalPlacesRt", }, Object { "key": "trace_continuation_strategy", @@ -407,7 +407,7 @@ Array [ Object { "key": "transaction_sample_rate", "type": "float", - "validationName": "floatRt", + "validationName": "floatFourDecimalPlacesRt", }, Object { "key": "unnest_exceptions", diff --git a/x-pack/plugins/observability_solution/apm/common/agent_configuration/setting_definitions/index.ts b/x-pack/plugins/observability_solution/apm/common/agent_configuration/setting_definitions/index.ts index 200ce169a05f1..ce675efa094e5 100644 --- a/x-pack/plugins/observability_solution/apm/common/agent_configuration/setting_definitions/index.ts +++ b/x-pack/plugins/observability_solution/apm/common/agent_configuration/setting_definitions/index.ts @@ -13,7 +13,8 @@ import { AgentName } from '../../../typings/es_schemas/ui/fields/agent'; import { booleanRt } from '../runtime_types/boolean_rt'; import { getIntegerRt } from '../runtime_types/integer_rt'; import { isRumOrMobileAgentName } from '../../agent_name'; -import { floatRt } from '../runtime_types/float_rt'; +import { floatThreeDecimalPlacesRt } from '../runtime_types/float_three_decimal_places_rt'; +import { floatFourDecimalPlacesRt } from '../runtime_types/float_four_decimal_places_rt'; import { RawSettingDefinition, SettingDefinition } from './types'; import { generalSettings } from './general_settings'; import { javaSettings } from './java_settings'; @@ -45,8 +46,14 @@ function getSettingDefaults(setting: RawSettingDefinition): SettingDefinition { } case 'float': { + if (setting.key === 'transaction_sample_rate') { + return { + validation: floatFourDecimalPlacesRt, + ...setting, + }; + } return { - validation: floatRt, + validation: floatThreeDecimalPlacesRt, ...setting, }; } diff --git a/x-pack/plugins/observability_solution/apm/server/types.ts b/x-pack/plugins/observability_solution/apm/server/types.ts index 1aeb6defe9a57..84e0d5462c43b 100644 --- a/x-pack/plugins/observability_solution/apm/server/types.ts +++ b/x-pack/plugins/observability_solution/apm/server/types.ts @@ -26,10 +26,7 @@ import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server'; import { ActionsPlugin } from '@kbn/actions-plugin/server'; import { AlertingPlugin } from '@kbn/alerting-plugin/server'; import { CloudSetup } from '@kbn/cloud-plugin/server'; -import { - PluginSetupContract as FeaturesPluginSetup, - PluginStartContract as FeaturesPluginStart, -} from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup, FeaturesPluginStart } from '@kbn/features-plugin/server'; import { LicensingPluginSetup, LicensingPluginStart } from '@kbn/licensing-plugin/server'; import { MlPluginSetup, MlPluginStart } from '@kbn/ml-plugin/server'; import { ObservabilityPluginSetup } from '@kbn/observability-plugin/server'; diff --git a/x-pack/plugins/observability_solution/dataset_quality/common/constants.ts b/x-pack/plugins/observability_solution/dataset_quality/common/constants.ts index ec2a9f6f641db..a6c6754befb8e 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/common/constants.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/common/constants.ts @@ -38,3 +38,6 @@ export const BYTE_NUMBER_FORMAT = '0.0 b'; export const MAX_HOSTS_METRIC_VALUE = 50; export const MAX_DEGRADED_FIELDS = 1000; + +export const MASKED_FIELD_PLACEHOLDER = ''; +export const UNKOWN_FIELD_PLACEHOLDER = ''; diff --git a/x-pack/plugins/observability_solution/dataset_quality/kibana.jsonc b/x-pack/plugins/observability_solution/dataset_quality/kibana.jsonc index c45b3c756d119..413917f62bd7f 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/kibana.jsonc +++ b/x-pack/plugins/observability_solution/dataset_quality/kibana.jsonc @@ -22,7 +22,8 @@ "fleet", "fieldFormats", "dataViews", - "lens" + "lens", + "fieldsMetadata" ], "optionalPlugins": [], "requiredBundles": ["unifiedHistogram", "discover"], diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_docs_trend/degraded_docs.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_docs_trend/degraded_docs.tsx index 5a13b717ca336..c1c6bdf23f7c4 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_docs_trend/degraded_docs.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_docs_trend/degraded_docs.tsx @@ -56,7 +56,7 @@ export function DegradedDocs({ if (breakdown.dataViewField && !breakdown.fieldSupportsBreakdown) { // TODO: If needed, notify user that the field is not breakable } - }, [setBreakdownDataViewField, breakdown.dataViewField, breakdown.fieldSupportsBreakdown]); + }, [setBreakdownDataViewField, breakdown]); return ( diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/controller/create_controller.ts b/x-pack/plugins/observability_solution/dataset_quality/public/controller/create_controller.ts index 899ec4c672afa..3d8e808adfcfb 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/controller/create_controller.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/controller/create_controller.ts @@ -16,6 +16,7 @@ import { createDatasetQualityControllerStateMachine, DEFAULT_CONTEXT, } from '../state_machines/dataset_quality_controller'; +import { DatasetQualityStartDeps } from '../types'; import { getContextFromPublicState, getPublicStateFromContext } from './public_state'; import { DatasetQualityController, DatasetQualityPublicStateUpdate } from './types'; @@ -23,12 +24,13 @@ type InitialState = DatasetQualityPublicStateUpdate; interface Dependencies { core: CoreStart; + plugins: DatasetQualityStartDeps; dataStreamStatsClient: IDataStreamsStatsClient; dataStreamDetailsClient: IDataStreamDetailsClient; } export const createDatasetQualityControllerFactory = - ({ core, dataStreamStatsClient, dataStreamDetailsClient }: Dependencies) => + ({ core, plugins, dataStreamStatsClient, dataStreamDetailsClient }: Dependencies) => async ({ initialState = DEFAULT_CONTEXT, }: { @@ -38,6 +40,7 @@ export const createDatasetQualityControllerFactory = const machine = createDatasetQualityControllerStateMachine({ initialContext, + plugins, toasts: core.notifications.toasts, dataStreamStatsClient, dataStreamDetailsClient, diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs_chart.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs_chart.tsx index 9d459f8227a40..682f0205c7438 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs_chart.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs_chart.tsx @@ -8,7 +8,7 @@ import { useCallback, useState, useMemo, useEffect } from 'react'; import { Action } from '@kbn/ui-actions-plugin/public'; import { fieldSupportsBreakdown } from '@kbn/unified-histogram-plugin/public'; - +import { useSelector } from '@xstate/react'; import { i18n } from '@kbn/i18n'; import { useEuiTheme } from '@elastic/eui'; import { type DataView, DataViewField } from '@kbn/data-views-plugin/common'; @@ -53,11 +53,29 @@ export const useDegradedDocsChart = ({ dataStream }: DegradedDocsChartDeps) => { services: { lens }, } = useKibanaContextForPlugin(); const { service } = useDatasetQualityContext(); - const { trackDetailsNavigated, navigationTargets, navigationSources } = - useDatasetDetailsTelemetry(); + + const { + trackDatasetDetailsBreakdownFieldChanged, + trackDetailsNavigated, + navigationTargets, + navigationSources, + } = useDatasetDetailsTelemetry(); const { dataStreamStat, timeRange, breakdownField } = useDatasetQualityFlyout(); + const isBreakdownFieldEcs = useSelector( + service, + (state) => state.context.flyout.isBreakdownFieldEcs + ); + + const isBreakdownFieldEcsAsserted = useSelector(service, (state) => { + return ( + state.matches('flyout.initializing.assertBreakdownFieldIsEcs.done') && + state.history?.matches('flyout.initializing.assertBreakdownFieldIsEcs.fetching') && + isBreakdownFieldEcs !== null + ); + }); + const [isChartLoading, setIsChartLoading] = useState(undefined); const [attributes, setAttributes] = useState | undefined>( undefined @@ -86,6 +104,10 @@ export const useDegradedDocsChart = ({ dataStream }: DegradedDocsChartDeps) => { [service] ); + useEffect(() => { + if (isBreakdownFieldEcsAsserted) trackDatasetDetailsBreakdownFieldChanged(); + }, [trackDatasetDetailsBreakdownFieldChanged, isBreakdownFieldEcsAsserted]); + useEffect(() => { const dataStreamName = dataStream ?? DEFAULT_LOGS_DATA_VIEW; diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_telemetry.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_telemetry.tsx index e5fc1088e7466..f32deb8e3b2c2 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_telemetry.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_telemetry.tsx @@ -11,6 +11,7 @@ import { useSelector } from '@xstate/react'; import { getDateISORange } from '@kbn/timerange'; import { AggregateQuery, Query } from '@kbn/es-query'; +import { MASKED_FIELD_PLACEHOLDER, UNKOWN_FIELD_PLACEHOLDER } from '../../common/constants'; import { DataStreamStat } from '../../common/data_streams_stats'; import { DataStreamDetails } from '../../common/api_types'; import { mapPercentageToQuality } from '../../common/utils'; @@ -143,10 +144,13 @@ export const useDatasetDetailsTelemetry = () => { insightsTimeRange, breakdownField, isNonAggregatable, + isBreakdownFieldEcs, } = useSelector(service, (state) => state.context.flyout) ?? {}; const loadingState = useSelector(service, (state) => ({ - dataStreamDetailsLoading: state.matches('flyout.initializing.dataStreamDetails.fetching'), + dataStreamDetailsLoading: + state.matches('flyout.initializing.dataStreamDetails.fetching') || + state.matches('flyout.initializing.assertBreakdownFieldIsEcs.fetching'), })); const canUserAccessDashboards = useSelector( @@ -173,6 +177,7 @@ export const useDatasetDetailsTelemetry = () => { isNonAggregatable ?? false, canUserViewIntegrations, canUserAccessDashboards, + isBreakdownFieldEcs, breakdownField ); } @@ -186,6 +191,7 @@ export const useDatasetDetailsTelemetry = () => { isNonAggregatable, canUserViewIntegrations, canUserAccessDashboards, + isBreakdownFieldEcs, breakdownField, ]); @@ -225,6 +231,19 @@ export const useDatasetDetailsTelemetry = () => { [ebtProps, telemetryClient] ); + const trackDatasetDetailsBreakdownFieldChanged = useCallback(() => { + const datasetDetailsTrackingState = telemetryClient.getDatasetDetailsTrackingState(); + if ( + (datasetDetailsTrackingState === 'opened' || datasetDetailsTrackingState === 'navigated') && + ebtProps + ) { + telemetryClient.trackDatasetDetailsBreakdownFieldChanged({ + ...ebtProps, + breakdown_field: ebtProps.breakdown_field, + }); + } + }, [ebtProps, telemetryClient]); + const wrapLinkPropsForTelemetry = useCallback( ( props: RouterLinkProps, @@ -251,6 +270,7 @@ export const useDatasetDetailsTelemetry = () => { wrapLinkPropsForTelemetry, navigationTargets: NavigationTarget, navigationSources: NavigationSource, + trackDatasetDetailsBreakdownFieldChanged, }; }; @@ -318,6 +338,7 @@ function getDatasetDetailsEbtProps( isNonAggregatable: boolean, canUserViewIntegrations: boolean, canUserAccessDashboards: boolean, + isBreakdownFieldEcs: boolean | null, breakdownField?: string ): DatasetDetailsEbtProps { const indexName = flyoutDataset.rawName; @@ -347,6 +368,14 @@ function getDatasetDetailsEbtProps( to, degraded_percentage: degradedPercentage, integration: flyoutDataset.integration?.name, - breakdown_field: breakdownField, + breakdown_field: breakdownField + ? isBreakdownFieldEcs === null + ? UNKOWN_FIELD_PLACEHOLDER + : getMaskedBreakdownField(breakdownField, isBreakdownFieldEcs) + : breakdownField, }; } + +function getMaskedBreakdownField(breakdownField: string, isBreakdownFieldEcs: boolean) { + return isBreakdownFieldEcs ? breakdownField : MASKED_FIELD_PLACEHOLDER; +} diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/plugin.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/plugin.tsx index 3e90347875ba8..d24408a85532d 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/plugin.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/plugin.tsx @@ -49,6 +49,7 @@ export class DatasetQualityPlugin const createDatasetQualityController = createDatasetQualityControllerLazyFactory({ core, + plugins, dataStreamStatsClient, dataStreamDetailsClient, }); diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_client.ts b/x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_client.ts index c0e93f13cd1b3..bf73c3b695aa2 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_client.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_client.ts @@ -55,4 +55,11 @@ export class TelemetryClient implements ITelemetryClient { tracking_id: this.datasetDetailsTrackingId, }); }; + + public trackDatasetDetailsBreakdownFieldChanged = (eventProps: DatasetDetailsEbtProps) => { + this.analytics.reportEvent(DatasetQualityTelemetryEventTypes.BREAKDOWN_FIELD_CHANGED, { + ...eventProps, + tracking_id: this.datasetDetailsTrackingId, + }); + }; } diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_events.ts b/x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_events.ts index a8244a6830ae6..c5c6ce1501159 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_events.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_events.ts @@ -254,8 +254,29 @@ const datasetDetailsNavigatedEventType: DatasetQualityTelemetryEvent = { }, }; +const datasetDetailsBreakdownFieldChangedEventType: DatasetQualityTelemetryEvent = { + eventType: DatasetQualityTelemetryEventTypes.BREAKDOWN_FIELD_CHANGED, + schema: { + ...datasetCommonSchema, + tracking_id: { + type: 'keyword', + _meta: { + description: `Locally generated session tracking ID for funnel analysis`, + }, + }, + breakdown_field: { + type: 'keyword', + _meta: { + description: 'Field used for chart breakdown, if any', + optional: true, + }, + }, + }, +}; + export const datasetQualityEbtEvents = { datasetNavigatedEventType, datasetDetailsOpenedEventType, datasetDetailsNavigatedEventType, + datasetDetailsBreakdownFieldChangedEventType, }; diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_service.test.ts b/x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_service.test.ts index dfd1bd4fb2b51..958a5b419406f 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_service.test.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_service.test.ts @@ -174,4 +174,20 @@ describe('TelemetryService', () => { 'example_field' ); }); + + it('should report dataset details breakdown field change event', async () => { + const telemetry = service.start(); + const exampleEventData: DatasetDetailsEbtProps = { + ...defaultEbtProps, + breakdown_field: 'service.name', + }; + + telemetry.trackDatasetDetailsBreakdownFieldChanged(exampleEventData); + + expect(mockCoreStart.analytics.reportEvent).toHaveBeenCalledTimes(1); + expect(mockCoreStart.analytics.reportEvent).toHaveBeenCalledWith( + datasetQualityEbtEvents.datasetDetailsBreakdownFieldChangedEventType.eventType, + expect.objectContaining(exampleEventData) + ); + }); }); diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_service.ts b/x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_service.ts index f8f8c5322f556..45f1221cebd32 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_service.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_service.ts @@ -22,6 +22,9 @@ export class TelemetryService { analytics.registerEventType(datasetQualityEbtEvents.datasetNavigatedEventType); analytics.registerEventType(datasetQualityEbtEvents.datasetDetailsOpenedEventType); analytics.registerEventType(datasetQualityEbtEvents.datasetDetailsNavigatedEventType); + analytics.registerEventType( + datasetQualityEbtEvents.datasetDetailsBreakdownFieldChangedEventType + ); } public start(): ITelemetryClient { diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/types.ts b/x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/types.ts index 2784f02187db1..e4b5e07c8df92 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/types.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/types.ts @@ -101,12 +101,14 @@ export interface ITelemetryClient { getDatasetDetailsTrackingState: () => DatasetDetailsTrackingState; trackDatasetDetailsOpened: (eventProps: DatasetDetailsEbtProps) => void; trackDatasetDetailsNavigated: (eventProps: DatasetDetailsNavigatedEbtProps) => void; + trackDatasetDetailsBreakdownFieldChanged: (eventProps: DatasetDetailsEbtProps) => void; } export enum DatasetQualityTelemetryEventTypes { NAVIGATED = 'Dataset Quality Navigated', DETAILS_OPENED = 'Dataset Quality Dataset Details Opened', DETAILS_NAVIGATED = 'Dataset Quality Dataset Details Navigated', + BREAKDOWN_FIELD_CHANGED = 'Dataset Quality Dataset Details Breakdown Field Changed', } export type DatasetQualityTelemetryEvent = @@ -121,4 +123,8 @@ export type DatasetQualityTelemetryEvent = | { eventType: DatasetQualityTelemetryEventTypes.DETAILS_NAVIGATED; schema: RootSchema; + } + | { + eventType: DatasetQualityTelemetryEventTypes.BREAKDOWN_FIELD_CHANGED; + schema: RootSchema; }; diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/defaults.ts b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/defaults.ts index 90fe913c9113e..62ec47632c242 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/defaults.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/defaults.ts @@ -58,6 +58,7 @@ export const DEFAULT_CONTEXT: DefaultDatasetQualityControllerState = { }, }, }, + isBreakdownFieldEcs: null, }, datasets: [], isSizeStatsAvailable: true, diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/notifications.ts b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/notifications.ts index f92db44eb516c..fe83caafce250 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/notifications.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/notifications.ts @@ -93,3 +93,12 @@ export const noDatasetSelected = i18n.translate( defaultMessage: 'No data set have been selected', } ); + +export const assertBreakdownFieldEcsFailedNotifier = (toasts: IToasts, error: Error) => { + toasts.addDanger({ + title: i18n.translate('xpack.datasetQuality. assertBreakdownFieldEcsFailed', { + defaultMessage: "We couldn't retrieve breakdown field metadata.", + }), + text: error.message, + }); +}; diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/state_machine.ts b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/state_machine.ts index 6cad5ae252c0f..e2a6eda4d0e6e 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/state_machine.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/state_machine.ts @@ -8,6 +8,7 @@ import { IToasts } from '@kbn/core/public'; import { getDateISORange } from '@kbn/timerange'; import { assign, createMachine, DoneInvokeEvent, InterpreterFrom } from 'xstate'; +import { DatasetQualityStartDeps } from '../../../types'; import { Dashboard, DataStreamStat, DegradedFieldResponse } from '../../../../common/api_types'; import { Integration } from '../../../../common/data_streams_stats/integration'; import { IDataStreamDetailsClient } from '../../../services/data_stream_details'; @@ -18,6 +19,7 @@ import { GetIntegrationsParams, GetNonAggregatableDataStreamsParams, GetNonAggregatableDataStreamsResponse, + DataStreamStatServiceResponse, } from '../../../../common/data_streams_stats'; import { DegradedDocsStat } from '../../../../common/data_streams_stats/malformed_docs_stat'; import { DataStreamType } from '../../../../common/types'; @@ -35,6 +37,7 @@ import { noDatasetSelected, fetchNonAggregatableDatasetsFailedNotifier, fetchDataStreamIntegrationFailedNotifier, + assertBreakdownFieldEcsFailedNotifier, } from './notifications'; import { DatasetQualityControllerContext, @@ -354,6 +357,8 @@ export const createPureDatasetQualityControllerStateMachine = ( actions: ['storeFlyoutOptions'], }, BREAKDOWN_FIELD_CHANGE: { + target: + '#DatasetQualityController.flyout.initializing.assertBreakdownFieldIsEcs.fetching', actions: ['storeFlyoutOptions'], }, }, @@ -389,6 +394,25 @@ export const createPureDatasetQualityControllerStateMachine = ( }, }, }, + assertBreakdownFieldIsEcs: { + initial: 'fetching', + states: { + fetching: { + invoke: { + src: 'assertBreakdownFieldIsEcs', + onDone: { + target: 'done', + actions: ['storeBreakdownFieldIsEcs'], + }, + onError: { + target: 'done', + actions: ['notifyAssertBreakdownFieldEcsFailed'], + }, + }, + }, + done: {}, + }, + }, }, onDone: { target: '#DatasetQualityController.flyout.loaded', @@ -552,24 +576,35 @@ export const createPureDatasetQualityControllerStateMachine = ( }, }; }), + storeBreakdownFieldIsEcs: assign((context, event: DoneInvokeEvent) => { + return { + flyout: { + ...context.flyout, + isBreakdownFieldEcs: + 'data' in event && typeof event.data === 'boolean' ? event.data : null, + }, + }; + }), resetFlyoutOptions: assign((_context, _event) => ({ flyout: DEFAULT_CONTEXT.flyout })), - storeDataStreamStats: assign((_context, event) => { - if ('data' in event && 'dataStreamsStats' in event.data) { - const dataStreamStats = event.data.dataStreamsStats as DataStreamStat[]; - const datasetUserPrivileges = event.data.datasetUserPrivileges; + storeDataStreamStats: assign( + (_context, event: DoneInvokeEvent) => { + if ('data' in event && 'dataStreamsStats' in event.data) { + const dataStreamStats = event.data.dataStreamsStats as DataStreamStat[]; + const datasetUserPrivileges = event.data.datasetUserPrivileges; - // Check if any DataStreamStat has null; to check for serverless - const isSizeStatsAvailable = - !dataStreamStats.length || dataStreamStats.some((stat) => stat.totalDocs !== null); + // Check if any DataStreamStat has null; to check for serverless + const isSizeStatsAvailable = + !dataStreamStats.length || dataStreamStats.some((stat) => stat.totalDocs !== null); - return { - dataStreamStats, - isSizeStatsAvailable, - datasetUserPrivileges, - }; + return { + dataStreamStats, + isSizeStatsAvailable, + datasetUserPrivileges, + }; + } + return {}; } - return {}; - }), + ), storeDegradedDocStats: assign((_context, event) => { return 'data' in event ? { @@ -689,7 +724,12 @@ export const createPureDatasetQualityControllerStateMachine = ( }, guards: { checkIfActionForbidden: (context, event) => { - return 'data' in event && 'statusCode' in event.data && event.data.statusCode === 403; + return ( + 'data' in event && + typeof event.data === 'object' && + 'statusCode' in event.data! && + event.data.statusCode === 403 + ); }, }, } @@ -697,6 +737,7 @@ export const createPureDatasetQualityControllerStateMachine = ( export interface DatasetQualityControllerStateMachineDependencies { initialContext?: DatasetQualityControllerContext; + plugins: DatasetQualityStartDeps; toasts: IToasts; dataStreamStatsClient: IDataStreamsStatsClient; dataStreamDetailsClient: IDataStreamDetailsClient; @@ -704,6 +745,7 @@ export interface DatasetQualityControllerStateMachineDependencies { export const createDatasetQualityControllerStateMachine = ({ initialContext = DEFAULT_CONTEXT, + plugins, toasts, dataStreamStatsClient, dataStreamDetailsClient, @@ -728,6 +770,8 @@ export const createDatasetQualityControllerStateMachine = ({ const integrationName = context.flyout.datasetSettings?.integration; return fetchDataStreamIntegrationFailedNotifier(toasts, event.data, integrationName); }, + notifyAssertBreakdownFieldEcsFailed: (_context, event: DoneInvokeEvent) => + assertBreakdownFieldEcsFailedNotifier(toasts, event.data), }, services: { loadDataStreamStats: (context) => @@ -861,6 +905,27 @@ export const createDatasetQualityControllerStateMachine = ({ }), }); }, + assertBreakdownFieldIsEcs: async (context) => { + if (context.flyout.breakdownField) { + const allowedFieldSources = ['ecs', 'metadata']; + + // This timeout is to avoid a runtime error that randomly happens on breakdown field change + // TypeError: Cannot read properties of undefined (reading 'timeFieldName') + await new Promise((res) => setTimeout(res, 300)); + + const client = await plugins.fieldsMetadata.getClient(); + const { fields } = await client.find({ + attributes: ['source'], + fieldNames: [context.flyout.breakdownField], + }); + + const breakdownFieldSource = fields[context.flyout.breakdownField]?.source; + + return !!(breakdownFieldSource && allowedFieldSources.includes(breakdownFieldSource)); + } + + return null; + }, }, }); diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/types.ts b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/types.ts index 1454c098f9783..c258962f56b8d 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/types.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/types.ts @@ -76,6 +76,7 @@ export interface WithFlyoutOptions { degradedFields: DegradedFields; isNonAggregatable?: boolean; integration?: DataStreamIntegrations; + isBreakdownFieldEcs: boolean | null; }; } @@ -166,6 +167,18 @@ export type DatasetQualityControllerTypeState = value: 'flyout.initializing.dataStreamDetails.fetching'; context: DefaultDatasetQualityStateContext; } + | { + value: 'flyout.initializing.dataStreamDetails.done'; + context: DefaultDatasetQualityStateContext; + } + | { + value: 'flyout.initializing.assertBreakdownFieldIsEcs.fetching'; + context: DefaultDatasetQualityStateContext; + } + | { + value: 'flyout.initializing.assertBreakdownFieldIsEcs.done'; + context: DefaultDatasetQualityStateContext; + } | { value: 'flyout.initializing.dataStreamDegradedFields.fetching'; context: DefaultDatasetQualityStateContext; @@ -244,4 +257,5 @@ export type DatasetQualityControllerEvent = | DoneInvokeEvent | DoneInvokeEvent | DoneInvokeEvent + | DoneInvokeEvent | DoneInvokeEvent; diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/types.ts b/x-pack/plugins/observability_solution/dataset_quality/public/types.ts index 7da7875978740..bcdd001cb6843 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/types.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/types.ts @@ -13,6 +13,7 @@ import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/ import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import type { LensPublicStart } from '@kbn/lens-plugin/public'; import type { ObservabilitySharedPluginSetup } from '@kbn/observability-shared-plugin/public'; +import type { FieldsMetadataPublicStart } from '@kbn/fields-metadata-plugin/public'; import type { CreateDatasetQualityController } from './controller'; import type { DatasetQualityProps } from './components/dataset_quality'; @@ -33,6 +34,7 @@ export interface DatasetQualityStartDeps { lens: LensPublicStart; dataViews: DataViewsPublicPluginStart; observabilityShared: ObservabilitySharedPluginSetup; + fieldsMetadata: FieldsMetadataPublicStart; } export interface DatasetQualitySetupDeps { diff --git a/x-pack/plugins/observability_solution/dataset_quality/tsconfig.json b/x-pack/plugins/observability_solution/dataset_quality/tsconfig.json index 13e698502a7a2..0ea6e9df38b7e 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/tsconfig.json +++ b/x-pack/plugins/observability_solution/dataset_quality/tsconfig.json @@ -52,7 +52,8 @@ "@kbn/shared-ux-prompt-no-data-views-types", "@kbn/core-analytics-server", "@kbn/ebt", - "@kbn/ebt-tools" + "@kbn/ebt-tools", + "@kbn/fields-metadata-plugin" ], "exclude": [ "target/**/*" diff --git a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/helpers/fixtures/entity_definition.ts b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/helpers/fixtures/entity_definition.ts index 137560df13385..2d6bceda8b077 100644 --- a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/helpers/fixtures/entity_definition.ts +++ b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/helpers/fixtures/entity_definition.ts @@ -6,7 +6,7 @@ */ import { entityDefinitionSchema } from '@kbn/entities-schema'; -export const entityDefinition = entityDefinitionSchema.parse({ +export const rawEntityDefinition = { id: 'admin-console-services', version: '999.999.999', name: 'Services for Admin Console', @@ -43,4 +43,5 @@ export const entityDefinition = entityDefinitionSchema.parse({ ], }, ], -}); +}; +export const entityDefinition = entityDefinitionSchema.parse(rawEntityDefinition); diff --git a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/transform/generate_metadata_aggregations.test.ts b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/transform/generate_metadata_aggregations.test.ts new file mode 100644 index 0000000000000..0ae3c4a81c870 --- /dev/null +++ b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/transform/generate_metadata_aggregations.test.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { entityDefinitionSchema } from '@kbn/entities-schema'; +import { rawEntityDefinition } from '../helpers/fixtures/entity_definition'; +import { + generateHistoryMetadataAggregations, + generateLatestMetadataAggregations, +} from './generate_metadata_aggregations'; + +describe('Generate Metadata Aggregations for history and latest', () => { + describe('generateHistoryMetadataAggregations()', () => { + it('should generate metadata aggregations for string format', () => { + const definition = entityDefinitionSchema.parse({ + ...rawEntityDefinition, + metadata: ['host.name'], + }); + expect(generateHistoryMetadataAggregations(definition)).toEqual({ + 'entity.metadata.host.name': { + terms: { + field: 'host.name', + size: 1000, + }, + }, + }); + }); + + it('should generate metadata aggregations for object format with only source', () => { + const definition = entityDefinitionSchema.parse({ + ...rawEntityDefinition, + metadata: [{ source: 'host.name' }], + }); + expect(generateHistoryMetadataAggregations(definition)).toEqual({ + 'entity.metadata.host.name': { + terms: { + field: 'host.name', + size: 1000, + }, + }, + }); + }); + + it('should generate metadata aggregations for object format with source and limit', () => { + const definition = entityDefinitionSchema.parse({ + ...rawEntityDefinition, + metadata: [{ source: 'host.name', limit: 10 }], + }); + expect(generateHistoryMetadataAggregations(definition)).toEqual({ + 'entity.metadata.host.name': { + terms: { + field: 'host.name', + size: 10, + }, + }, + }); + }); + + it('should generate metadata aggregations for object format with source, limit, and destination', () => { + const definition = entityDefinitionSchema.parse({ + ...rawEntityDefinition, + metadata: [{ source: 'host.name', limit: 10, destination: 'hostName' }], + }); + expect(generateHistoryMetadataAggregations(definition)).toEqual({ + 'entity.metadata.hostName': { + terms: { + field: 'host.name', + size: 10, + }, + }, + }); + }); + }); + + describe('generateLatestMetadataAggregations()', () => { + it('should generate metadata aggregations for string format', () => { + const definition = entityDefinitionSchema.parse({ + ...rawEntityDefinition, + metadata: ['host.name'], + }); + expect(generateLatestMetadataAggregations(definition)).toEqual({ + 'entity.metadata.host.name': { + filter: { + range: { + 'event.ingested': { + gte: 'now-1m', + }, + }, + }, + aggs: { + data: { + terms: { + field: 'host.name', + size: 1000, + }, + }, + }, + }, + }); + }); + + it('should generate metadata aggregations for object format with only source', () => { + const definition = entityDefinitionSchema.parse({ + ...rawEntityDefinition, + metadata: [{ source: 'host.name' }], + }); + expect(generateLatestMetadataAggregations(definition)).toEqual({ + 'entity.metadata.host.name': { + filter: { + range: { + 'event.ingested': { + gte: 'now-1m', + }, + }, + }, + aggs: { + data: { + terms: { + field: 'host.name', + size: 1000, + }, + }, + }, + }, + }); + }); + + it('should generate metadata aggregations for object format with source and limit', () => { + const definition = entityDefinitionSchema.parse({ + ...rawEntityDefinition, + metadata: [{ source: 'host.name', limit: 10 }], + }); + expect(generateLatestMetadataAggregations(definition)).toEqual({ + 'entity.metadata.host.name': { + filter: { + range: { + 'event.ingested': { + gte: 'now-1m', + }, + }, + }, + aggs: { + data: { + terms: { + field: 'host.name', + size: 10, + }, + }, + }, + }, + }); + }); + + it('should generate metadata aggregations for object format with source, limit, and destination', () => { + const definition = entityDefinitionSchema.parse({ + ...rawEntityDefinition, + metadata: [{ source: 'host.name', limit: 10, destination: 'hostName' }], + }); + expect(generateLatestMetadataAggregations(definition)).toEqual({ + 'entity.metadata.hostName': { + filter: { + range: { + 'event.ingested': { + gte: 'now-1m', + }, + }, + }, + aggs: { + data: { + terms: { + field: 'hostName', + size: 10, + }, + }, + }, + }, + }); + }); + }); +}); diff --git a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/transform/generate_metadata_aggregations.ts b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/transform/generate_metadata_aggregations.ts index 31ba3e9add0dc..809ed5f2b57b9 100644 --- a/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/transform/generate_metadata_aggregations.ts +++ b/x-pack/plugins/observability_solution/entity_manager/server/lib/entities/transform/generate_metadata_aggregations.ts @@ -34,7 +34,7 @@ export function generateLatestMetadataAggregations(definition: EntityDefinition) return definition.metadata.reduce( (aggs, metadata) => ({ ...aggs, - [`entity.metadata.${metadata.destination}`]: { + [`entity.metadata.${metadata.destination ?? metadata.source}`]: { filter: { range: { 'event.ingested': { diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/profiling/functions.tsx b/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/profiling/functions.tsx index 500eda5c10783..811172fca2695 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/profiling/functions.tsx +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/profiling/functions.tsx @@ -85,6 +85,7 @@ export function Functions({ kuery }: Props) { isLoading={isPending(status)} rangeFrom={from} rangeTo={to} + height="60vh" /> ); diff --git a/x-pack/plugins/observability_solution/infra/server/lib/adapters/framework/adapter_types.ts b/x-pack/plugins/observability_solution/infra/server/lib/adapters/framework/adapter_types.ts index 398eaa0ccf3b8..8fe4101d7ebca 100644 --- a/x-pack/plugins/observability_solution/infra/server/lib/adapters/framework/adapter_types.ts +++ b/x-pack/plugins/observability_solution/infra/server/lib/adapters/framework/adapter_types.ts @@ -18,7 +18,7 @@ import { import { PluginStart as DataViewsPluginStart } from '@kbn/data-views-plugin/server'; import { HomeServerPluginSetup } from '@kbn/home-plugin/server'; import { VisTypeTimeseriesSetup } from '@kbn/vis-type-timeseries-plugin/server'; -import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { SpacesPluginSetup } from '@kbn/spaces-plugin/server'; import { PluginSetupContract as AlertingPluginContract } from '@kbn/alerting-plugin/server'; import { MlPluginSetup } from '@kbn/ml-plugin/server'; diff --git a/x-pack/plugins/observability_solution/metrics_data_access/server/lib/adapters/framework/adapter_types.ts b/x-pack/plugins/observability_solution/metrics_data_access/server/lib/adapters/framework/adapter_types.ts index d55c1aad0408f..daea1177b19f8 100644 --- a/x-pack/plugins/observability_solution/metrics_data_access/server/lib/adapters/framework/adapter_types.ts +++ b/x-pack/plugins/observability_solution/metrics_data_access/server/lib/adapters/framework/adapter_types.ts @@ -18,7 +18,7 @@ import { import { PluginStart as DataViewsPluginStart } from '@kbn/data-views-plugin/server'; import { HomeServerPluginSetup } from '@kbn/home-plugin/server'; import { VisTypeTimeseriesSetup } from '@kbn/vis-type-timeseries-plugin/server'; -import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { SpacesPluginSetup } from '@kbn/spaces-plugin/server'; import { PluginSetupContract as AlertingPluginContract } from '@kbn/alerting-plugin/server'; import { MlPluginSetup } from '@kbn/ml-plugin/server'; diff --git a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/custom_threshold_rule_expression.test.tsx b/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/custom_threshold_rule_expression.test.tsx index 7ad399658caf1..1013a6ae2048c 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/custom_threshold_rule_expression.test.tsx +++ b/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/custom_threshold_rule_expression.test.tsx @@ -42,7 +42,7 @@ describe('Expression', () => { async function setup( currentOptions?: CustomThresholdPrefillOptions, - customRuleParams?: Record + customRuleParams?: Partial ) { const ruleParams: RuleTypeParams & AlertParams = { criteria: [], @@ -164,7 +164,8 @@ describe('Expression', () => { it('should prefill the rule using the context metadata', async () => { const index = 'changedMockedIndex'; const currentOptions: CustomThresholdPrefillOptions = { - alertOnGroupDisappear: false, + alertOnGroupDisappear: true, + alertOnNoData: true, groupBy: ['host.hostname'], searchConfiguration: { index, @@ -191,7 +192,8 @@ describe('Expression', () => { const { ruleParams } = await setup(currentOptions, { searchConfiguration: undefined }); - expect(ruleParams.alertOnGroupDisappear).toEqual(false); + expect(ruleParams.alertOnGroupDisappear).toEqual(true); + expect(ruleParams.alertOnNoData).toEqual(true); expect(ruleParams.groupBy).toEqual(['host.hostname']); expect((ruleParams.searchConfiguration.query as Query).query).toBe('foo'); expect(ruleParams.searchConfiguration.index).toBe(index); @@ -211,6 +213,68 @@ describe('Expression', () => { ]); }); + it('should only set alertOnGroupDisappear to true if there is a group by field', async () => { + const customRuleParams: Partial = { + groupBy: ['host.hostname'], + }; + + const { ruleParams, wrapper } = await setup({}, customRuleParams); + + act(() => { + wrapper + .find('[data-test-subj="thresholdRuleAlertOnNoDataCheckbox"]') + .at(1) + .prop('onChange')?.({ + target: { checked: true }, + } as React.ChangeEvent); + }); + + expect(ruleParams.alertOnGroupDisappear).toEqual(true); + expect(ruleParams.alertOnNoData).toEqual(false); + + // Uncheck + act(() => { + wrapper + .find('[data-test-subj="thresholdRuleAlertOnNoDataCheckbox"]') + .at(1) + .prop('onChange')?.({ + target: { checked: false }, + } as React.ChangeEvent); + }); + + expect(ruleParams.alertOnGroupDisappear).toEqual(false); + expect(ruleParams.alertOnNoData).toEqual(false); + }); + + it('should only set alertOnNoData to true if there is no group by', async () => { + const { ruleParams, wrapper } = await setup(); + + act(() => { + wrapper + .find('[data-test-subj="thresholdRuleAlertOnNoDataCheckbox"]') + .at(1) + .prop('onChange')?.({ + target: { checked: true }, + } as React.ChangeEvent); + }); + + expect(ruleParams.alertOnGroupDisappear).toEqual(false); + expect(ruleParams.alertOnNoData).toEqual(true); + + // Uncheck + act(() => { + wrapper + .find('[data-test-subj="thresholdRuleAlertOnNoDataCheckbox"]') + .at(1) + .prop('onChange')?.({ + target: { checked: false }, + } as React.ChangeEvent); + }); + + expect(ruleParams.alertOnGroupDisappear).toEqual(false); + expect(ruleParams.alertOnNoData).toEqual(false); + }); + it('should show an error message when searchSource throws an error', async () => { const errorMessage = 'Error in searchSource create'; const kibanaMock = kibanaStartMock.startContract(); diff --git a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/custom_threshold_rule_expression.tsx b/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/custom_threshold_rule_expression.tsx index 061805a709ea6..bbbcb59057824 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/custom_threshold_rule_expression.tsx +++ b/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/custom_threshold_rule_expression.tsx @@ -75,6 +75,11 @@ export default function Expressions(props: Props) { }, } = useKibana().services; + const hasGroupBy = useMemo( + () => !!ruleParams.groupBy && ruleParams.groupBy.length > 0, + [ruleParams.groupBy] + ); + const [timeSize, setTimeSize] = useState(1); const [timeUnit, setTimeUnit] = useState('m'); const [dataView, setDataView] = useState(); @@ -82,6 +87,10 @@ export default function Expressions(props: Props) { const [searchSource, setSearchSource] = useState(); const [paramsError, setParamsError] = useState(); const [paramsWarning, setParamsWarning] = useState(); + const [isNoDataChecked, setIsNoDataChecked] = useState( + (hasGroupBy && !!ruleParams.alertOnGroupDisappear) || + (!hasGroupBy && !!ruleParams.alertOnNoData) + ); const derivedIndexPattern = useMemo( () => ({ fields: dataView?.fields || [], @@ -177,11 +186,15 @@ export default function Expressions(props: Props) { } if (typeof ruleParams.alertOnNoData === 'undefined') { - setRuleParams('alertOnNoData', true); + preFillAlertOnNoData(); } if (typeof ruleParams.alertOnGroupDisappear === 'undefined') { preFillAlertOnGroupDisappear(); } + setIsNoDataChecked( + (hasGroupBy && !!ruleParams.alertOnGroupDisappear) || + (!hasGroupBy && !!ruleParams.alertOnNoData) + ); }, [metadata]); // eslint-disable-line react-hooks/exhaustive-deps const onSelectDataView = useCallback( @@ -250,9 +263,12 @@ export default function Expressions(props: Props) { const onGroupByChange = useCallback( (group: string | null | string[]) => { + const hasGroup = !!group && group.length > 0; setRuleParams('groupBy', group && group.length ? group : ''); + setRuleParams('alertOnGroupDisappear', hasGroup && isNoDataChecked); + setRuleParams('alertOnNoData', !hasGroup && isNoDataChecked); }, - [setRuleParams] + [setRuleParams, isNoDataChecked] ); const emptyError = useMemo(() => { @@ -314,20 +330,24 @@ export default function Expressions(props: Props) { } }, [metadata, setRuleParams]); + const preFillAlertOnNoData = useCallback(() => { + const md = metadata; + if (md && typeof md.currentOptions?.alertOnNoData !== 'undefined') { + setRuleParams('alertOnNoData', md.currentOptions.alertOnNoData); + } else { + setRuleParams('alertOnNoData', false); + } + }, [metadata, setRuleParams]); + const preFillAlertOnGroupDisappear = useCallback(() => { const md = metadata; if (md && typeof md.currentOptions?.alertOnGroupDisappear !== 'undefined') { setRuleParams('alertOnGroupDisappear', md.currentOptions.alertOnGroupDisappear); } else { - setRuleParams('alertOnGroupDisappear', true); + setRuleParams('alertOnGroupDisappear', false); } }, [metadata, setRuleParams]); - const hasGroupBy = useMemo( - () => ruleParams.groupBy && ruleParams.groupBy.length > 0, - [ruleParams.groupBy] - ); - if (paramsError) { return ( <> @@ -540,30 +560,55 @@ export default function Expressions(props: Props) { {i18n.translate( 'xpack.observability.customThreshold.rule.alertFlyout.alertOnGroupDisappear', { - defaultMessage: 'Alert me if a group stops reporting data', + defaultMessage: "Alert me if there's no data", } )}{' '} } - disabled={!hasGroupBy} - checked={Boolean(hasGroupBy && ruleParams.alertOnGroupDisappear)} - onChange={(e) => setRuleParams('alertOnGroupDisappear', e.target.checked)} + checked={isNoDataChecked} + onChange={(e) => { + const checked = e.target.checked; + setIsNoDataChecked(checked); + if (!checked) { + setRuleParams('alertOnGroupDisappear', false); + setRuleParams('alertOnNoData', false); + } else { + if (hasGroupBy) { + setRuleParams('alertOnGroupDisappear', true); + setRuleParams('alertOnNoData', false); + } else { + setRuleParams('alertOnGroupDisappear', false); + setRuleParams('alertOnNoData', true); + } + } + }} /> diff --git a/x-pack/plugins/observability_solution/observability/public/navigation_tree.ts b/x-pack/plugins/observability_solution/observability/public/navigation_tree.ts index aa627c89d3825..65256a1584461 100644 --- a/x-pack/plugins/observability_solution/observability/public/navigation_tree.ts +++ b/x-pack/plugins/observability_solution/observability/public/navigation_tree.ts @@ -228,6 +228,9 @@ const navTree: NavigationTreeDefinition = { defaultMessage: 'Logs stream', }), }, + { link: 'maps' }, + { link: 'canvas' }, + { link: 'graph' }, ], }, ], diff --git a/x-pack/plugins/observability_solution/observability/server/plugin.ts b/x-pack/plugins/observability_solution/observability/server/plugin.ts index dad2dd7ee572a..13d60368cd8d5 100644 --- a/x-pack/plugins/observability_solution/observability/server/plugin.ts +++ b/x-pack/plugins/observability_solution/observability/server/plugin.ts @@ -20,7 +20,7 @@ import { PluginInitializerContext, } from '@kbn/core/server'; import { LogsExplorerLocatorParams, LOGS_EXPLORER_LOCATOR_ID } from '@kbn/deeplinks-observability'; -import { PluginSetupContract as FeaturesSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { hiddenTypes as filesSavedObjectTypes } from '@kbn/files-plugin/server/saved_objects'; import type { GuidedOnboardingPluginSetup } from '@kbn/guided-onboarding-plugin/server'; import { i18n } from '@kbn/i18n'; @@ -60,7 +60,7 @@ export type ObservabilityPluginSetup = ReturnType; interface PluginSetup { alerting: PluginSetupContract; - features: FeaturesSetup; + features: FeaturesPluginSetup; guidedOnboarding?: GuidedOnboardingPluginSetup; ruleRegistry: RuleRegistryPluginSetupContract; share: SharePluginSetup; diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/types.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/types.ts index dc84d58bef9e9..a8ab57b8ee53c 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/types.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/types.ts @@ -4,10 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { - PluginStartContract as FeaturesPluginStart, - PluginSetupContract as FeaturesPluginSetup, -} from '@kbn/features-plugin/server'; +import type { FeaturesPluginStart, FeaturesPluginSetup } from '@kbn/features-plugin/server'; import type { PluginSetupContract as ActionsPluginSetup, PluginStartContract as ActionsPluginStart, diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/functions/visualize_esql.tsx b/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/functions/visualize_esql.tsx index 9442a73751628..e81e30b0beec7 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/functions/visualize_esql.tsx +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/functions/visualize_esql.tsx @@ -18,7 +18,7 @@ import { import type { ESQLRow } from '@kbn/es-types'; import { ESQLDataGrid } from '@kbn/esql-datagrid/public'; import type { DataViewsServicePublic } from '@kbn/data-views-plugin/public/types'; -import { getESQLAdHocDataview, getIndexPatternFromESQLQuery } from '@kbn/esql-utils'; +import { getESQLAdHocDataview } from '@kbn/esql-utils'; import type { DatatableColumn } from '@kbn/expressions-plugin/common'; import { i18n } from '@kbn/i18n'; import type { @@ -117,15 +117,13 @@ export function VisualizeESQL({ ObservabilityAIAssistantMultipaneFlyoutContext, errorMessages, }: VisualizeESQLProps) { - // fetch the pattern from the query - const indexPattern = getIndexPatternFromESQLQuery(query); const lensHelpersAsync = useAsync(() => { return lens.stateHelperApi(); }, [lens]); const dataViewAsync = useAsync(() => { - return getESQLAdHocDataview(indexPattern, dataViews); - }, [indexPattern, dataViews]); + return getESQLAdHocDataview(query, dataViews); + }, [query, dataViews]); const chatFlyoutSecondSlotHandler = useContext(ObservabilityAIAssistantMultipaneFlyoutContext); diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/types.ts b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/types.ts index 680e5b2409b7c..30cce3f0b37b3 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/types.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/types.ts @@ -17,10 +17,7 @@ import type { DataViewsServerPluginSetup, DataViewsServerPluginStart, } from '@kbn/data-views-plugin/server'; -import type { - PluginStartContract as FeaturesPluginStart, - PluginSetupContract as FeaturesPluginSetup, -} from '@kbn/features-plugin/server'; +import type { FeaturesPluginStart, FeaturesPluginSetup } from '@kbn/features-plugin/server'; import type { LicensingPluginSetup, LicensingPluginStart } from '@kbn/licensing-plugin/server'; import type { ObservabilityAIAssistantServerSetup, diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/onboarding_flow_form/onboarding_flow_form.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/onboarding_flow_form/onboarding_flow_form.tsx index 4d5e75abe74c4..f926e4d1d88ee 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/onboarding_flow_form/onboarding_flow_form.tsx +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/onboarding_flow_form/onboarding_flow_form.tsx @@ -8,7 +8,6 @@ import { i18n } from '@kbn/i18n'; import React, { useCallback, useEffect, useRef, useState } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; -import { useKibana } from '@kbn/kibana-react-plugin/public'; import type { FunctionComponent } from 'react'; import { EuiAvatar, @@ -22,7 +21,6 @@ import { useGeneratedHtmlId, useEuiTheme, EuiBadge, - EuiIcon, } from '@elastic/eui'; import { useSearchParams } from 'react-router-dom-v5-compat'; @@ -31,6 +29,7 @@ import { useCustomMargin } from '../shared/use_custom_margin'; import { Category } from './types'; import { useCustomCardsForCategory } from './use_custom_cards_for_category'; import { useVirtualSearchResults } from './use_virtual_search_results'; +import { LogoIcon, SupportedLogo } from '../shared/logo_icon'; interface UseCaseOption { id: Category; @@ -40,19 +39,6 @@ interface UseCaseOption { showIntegrationsBadge?: boolean; } -type SupportedLogo = - | 'aws' - | 'azure' - | 'docker' - | 'dotnet' - | 'prometheus' - | 'gcp' - | 'java' - | 'javascript' - | 'kubernetes' - | 'nginx' - | 'opentelemetry'; - export const OnboardingFlowForm: FunctionComponent = () => { const options: UseCaseOption[] = [ { @@ -306,35 +292,3 @@ function scrollIntoViewWithOffset(element: HTMLElement, offset = 0) { top: element.getBoundingClientRect().top - document.body.getBoundingClientRect().top - offset, }); } - -function useIconForLogo(logo?: SupportedLogo): string | undefined { - const { - services: { http }, - } = useKibana(); - switch (logo) { - case 'aws': - return 'logoAWS'; - case 'azure': - return 'logoAzure'; - case 'gcp': - return 'logoGCP'; - case 'kubernetes': - return 'logoKubernetes'; - case 'nginx': - return 'logoNginx'; - case 'prometheus': - return 'logoPrometheus'; - case 'docker': - return 'logoDocker'; - default: - return http?.staticAssets.getPluginAssetHref(`${logo}.svg`); - } -} - -function LogoIcon({ logo }: { logo: SupportedLogo }) { - const iconType = useIconForLogo(logo); - if (iconType) { - return ; - } - return null; -} diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/onboarding_flow_form/use_custom_cards_for_category.ts b/x-pack/plugins/observability_solution/observability_onboarding/public/application/onboarding_flow_form/use_custom_cards_for_category.ts index 03d7d0278f374..1da487e5a17cd 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/onboarding_flow_form/use_custom_cards_for_category.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/onboarding_flow_form/use_custom_cards_for_category.ts @@ -31,7 +31,7 @@ export function useCustomCardsForCategory( } = useKibana(); const getUrlForApp = application?.getUrlForApp; - const { href: systemLogsUrl } = reactRouterNavigate(history, `/systemLogs/${location.search}`); + const { href: autoDetectUrl } = reactRouterNavigate(history, `/auto-detect/${location.search}`); const { href: customLogsUrl } = reactRouterNavigate(history, `/customLogs/${location.search}`); const { href: otelLogsUrl } = reactRouterNavigate(history, `/otel-logs/${location.search}`); const { href: kubernetesUrl } = reactRouterNavigate(history, `/kubernetes/${location.search}`); @@ -42,7 +42,7 @@ export function useCustomCardsForCategory( release: 'preview', title: 'OpenTelemetry', description: - 'Collect Logs and host metrics using the Elastic distribution of the OpenTelemetry Collector', + 'Collect logs and host metrics using the Elastic distribution of the OpenTelemetry Collector', name: 'custom-logs-virtual', categories: ['observability'], icons: [ @@ -117,6 +117,7 @@ export function useCustomCardsForCategory( id: 'kubernetes-quick-start', type: 'virtual', title: 'Kubernetes', + release: 'preview', description: 'Collect logs and metrics from Kubernetes using minimal configuration', name: 'kubernetes-quick-start', categories: ['observability'], @@ -178,19 +179,20 @@ export function useCustomCardsForCategory( case 'logs': return [ { - id: 'system-logs', + id: 'auto-detect-logs', type: 'virtual', - title: 'Stream host system logs', - description: 'Collect system logs from your machine or server', - name: 'system-logs-virtual', + title: 'Auto-detect logs and metrics', + release: 'preview', + description: 'This installation scans your host and auto-detects log files and metrics', + name: 'auto-detect-logs-virtual', categories: ['observability'], icons: [ { - type: 'svg', - src: http?.staticAssets.getPluginAssetHref('system.svg') ?? '', + type: 'eui', + src: 'consoleApp', }, ], - url: systemLogsUrl, + url: autoDetectUrl, version: '', integration: '', }, diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/packages_list/utils.ts b/x-pack/plugins/observability_solution/observability_onboarding/public/application/packages_list/utils.ts index e0e468b0d80db..262f2f8dee709 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/packages_list/utils.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/packages_list/utils.ts @@ -7,7 +7,7 @@ import { IntegrationCardItem } from '@kbn/fleet-plugin/public'; -export const QUICKSTART_FLOWS = ['system-logs-virtual', 'kubernetes-quick-start']; +export const QUICKSTART_FLOWS = ['auto-detect-logs-virtual', 'kubernetes-quick-start']; export const toCustomCard = (card: IntegrationCardItem) => ({ ...card, diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/auto_detect/auto_detect_panel.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/auto_detect/auto_detect_panel.tsx index f9d1c7c4df608..fe2a0b5118b80 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/auto_detect/auto_detect_panel.tsx +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/auto_detect/auto_detect_panel.tsx @@ -17,30 +17,24 @@ import { EuiFlexGroup, EuiFlexItem, EuiText, - EuiImage, - EuiSkeletonRectangle, useGeneratedHtmlId, + EuiIcon, } from '@elastic/eui'; -import { useKibana } from '@kbn/kibana-react-plugin/public'; import { type SingleDatasetLocatorParams, SINGLE_DATASET_LOCATOR_ID, } from '@kbn/deeplinks-observability/locators'; -import { type DashboardLocatorParams } from '@kbn/dashboard-plugin/public'; -import { DASHBOARD_APP_LOCATOR } from '@kbn/deeplinks-analytics'; import { getAutoDetectCommand } from './get_auto_detect_command'; -import { useOnboardingFlow } from './use_onboarding_flow'; +import { DASHBOARDS, useOnboardingFlow } from './use_onboarding_flow'; import { ProgressIndicator } from '../shared/progress_indicator'; import { AccordionWithIcon } from '../shared/accordion_with_icon'; -import { type ObservabilityOnboardingContextValue } from '../../../plugin'; import { EmptyPrompt } from '../shared/empty_prompt'; import { CopyToClipboardButton } from '../shared/copy_to_clipboard_button'; import { LocatorButtonEmpty } from '../shared/locator_button_empty'; +import { GetStartedPanel } from '../shared/get_started_panel'; +import { isSupportedLogo, LogoIcon } from '../../shared/logo_icon'; export const AutoDetectPanel: FunctionComponent = () => { - const { - services: { http }, - } = useKibana(); const { status, data, error, refetch, installedIntegrations } = useOnboardingFlow(); const command = data ? getAutoDetectCommand(data) : undefined; const accordionId = useGeneratedHtmlId({ prefix: 'accordion' }); @@ -143,59 +137,73 @@ export const AutoDetectPanel: FunctionComponent = () => { + ) : ( + + ) + } title={i18n.translate( 'xpack.observability_onboarding.autoDetectPanel.h3.getStartedWithNginxLabel', { - defaultMessage: 'Get started with {title} logs', + defaultMessage: 'Get started with {title}', values: { title: integration.title }, } )} isDisabled={status !== 'dataReceived'} initialIsOpen > - - - {status === 'dataReceived' ? ( - - ) : ( - - )} - - -
      - {integration.kibanaAssets - .filter((asset) => asset.type === 'dashboard') - .map((dashboard) => ( -
    • - - locator={DASHBOARD_APP_LOCATOR} - params={{ dashboardId: dashboard.id }} - target="_blank" - iconType="dashboardApp" - isDisabled={status !== 'dataReceived'} - flush="left" - size="s" - > - {dashboard.attributes.title} - -
    • - ))} -
    -
    -
    + asset.type === 'dashboard') + .map((asset) => { + const dashboard = DASHBOARDS[asset.id as keyof typeof DASHBOARDS]; + + return { + id: asset.id, + title: + dashboard.type === 'metrics' + ? i18n.translate( + 'xpack.observability_onboarding.autoDetectPanel.exploreMetricsDataTitle', + { + defaultMessage: + 'Overview your metrics data with this pre-made dashboard', + } + ) + : i18n.translate( + 'xpack.observability_onboarding.autoDetectPanel.exploreLogsDataTitle', + { + defaultMessage: + 'Overview your logs data with this pre-made dashboard', + } + ), + label: + dashboard.type === 'metrics' + ? i18n.translate( + 'xpack.observability_onboarding.autoDetectPanel.exploreMetricsDataLabel', + { + defaultMessage: 'Explore metrics data', + } + ) + : i18n.translate( + 'xpack.observability_onboarding.autoDetectPanel.exploreLogsDataLabel', + { + defaultMessage: 'Explore logs data', + } + ), + }; + })} + />
    ))} {customIntegrations.length > 0 && ( } title={i18n.translate( 'xpack.observability_onboarding.autoDetectPanel.h3.getStartedWithlogLabel', { defaultMessage: 'Get started with custom .log files' } diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/auto_detect/use_onboarding_flow.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/auto_detect/use_onboarding_flow.tsx index 50f5636dd84b5..9a2c88517cffd 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/auto_detect/use_onboarding_flow.tsx +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/auto_detect/use_onboarding_flow.tsx @@ -14,6 +14,13 @@ import { getOnboardingStatus } from './get_onboarding_status'; import { getInstalledIntegrations } from './get_installed_integrations'; import { type ObservabilityOnboardingContextValue } from '../../../plugin'; +export const DASHBOARDS = { + 'apache-Logs-Apache-Dashboard': { type: 'logs' }, + 'docker-AV4REOpp5NkDleZmzKkE': { type: 'metrics' }, + 'nginx-55a9e6e0-a29e-11e7-928f-5dbe6f6f5519': { type: 'logs' }, + 'system-79ffd6e0-faa0-11e6-947f-177f697178b8': { type: 'metrics' }, +}; + export function useOnboardingFlow() { const { services: { fleet }, @@ -60,9 +67,11 @@ export function useOnboardingFlow() { return []; } const assetsMetadata = await fleet.hooks.epm.getBulkAssets({ - assetIds: installedIntegrations - .map((integration) => integration.kibanaAssets) - .flat() as AssetSOObject[], + assetIds: ( + installedIntegrations + .map((integration) => integration.kibanaAssets) + .flat() as AssetSOObject[] + ).filter((asset) => Object.keys(DASHBOARDS).includes(asset.id)), }); return installedIntegrations.map((integration) => { return { diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/kubernetes/data_ingest_status.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/kubernetes/data_ingest_status.tsx index 11fe5d2982343..0afb842ace19f 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/kubernetes/data_ingest_status.tsx +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/kubernetes/data_ingest_status.tsx @@ -6,19 +6,17 @@ */ import React, { useEffect, useState } from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiImage, EuiLink, EuiSpacer, EuiText } from '@elastic/eui'; +import { EuiLink, EuiSpacer, EuiText } from '@elastic/eui'; import { css } from '@emotion/react'; import { i18n } from '@kbn/i18n'; -import { useKibana } from '@kbn/kibana-react-plugin/public'; -import { DASHBOARD_APP_LOCATOR } from '@kbn/deeplinks-analytics'; import { FormattedMessage } from '@kbn/i18n-react'; import { StepsProgress, useFlowProgressTelemetry, } from '../../../hooks/use_flow_progress_telemetry'; -import { ObservabilityOnboardingContextValue } from '../../../plugin'; import { FETCH_STATUS, useFetcher } from '../../../hooks/use_fetcher'; import { ProgressIndicator } from '../shared/progress_indicator'; +import { GetStartedPanel } from '../shared/get_started_panel'; interface Props { onboardingId: string; @@ -29,14 +27,9 @@ const SHOW_TROUBLESHOOTING_DELAY = 120000; // 2 minutes const CLUSTER_OVERVIEW_DASHBOARD_ID = 'kubernetes-f4dc26db-1b53-4ea2-a78b-1bfab8ea267c'; export function DataIngestStatus({ onboardingId }: Props) { - const { - services: { share, http }, - } = useKibana(); const [progress, setProgress] = useState(undefined); const [checkDataStartTime] = useState(Date.now()); - const dashboardLocator = share.url.locators.get(DASHBOARD_APP_LOCATOR); - const { data, status, refetch } = useFetcher( (callApi) => { return callApi('GET /internal/observability_onboarding/kubernetes/{onboardingId}/has-data', { @@ -115,66 +108,28 @@ export function DataIngestStatus({ onboardingId }: Props) { <> - - - - - - - -

    - {i18n.translate( - 'xpack.observability_onboarding.kubernetesPanel.monitoringCluster', - { - defaultMessage: - 'Overview your Kubernetes cluster with this pre-made dashboard', - } - )} -

    -
    - - - {i18n.translate('xpack.observability_onboarding.kubernetesPanel.exploreDashboard', { - defaultMessage: 'Explore Kubernetes cluster', - })} - -
    -
    - - - - - - {i18n.translate( - 'xpack.observability_onboarding.dataIngestStatus.viewAllAssetsLinkText', - { - defaultMessage: 'View all assets', - } - )} - + - + title: i18n.translate( + 'xpack.observability_onboarding.kubernetesPanel.monitoringCluster', + { + defaultMessage: 'Overview your Kubernetes cluster with this pre-made dashboard', + } + ), + }, + ]} + /> )} diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/otel_logs/index.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/otel_logs/index.tsx index 0af2e38909176..d4f59e4b8171a 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/otel_logs/index.tsx +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/otel_logs/index.tsx @@ -438,6 +438,7 @@ data: - resourcedetection/gcp - resource/k8s - resource/cloud + - attributes/k8s_logs_dataset receivers: - filelog metrics: @@ -454,7 +455,6 @@ data: - resource/cloud - attributes/dataset - resource/process - - attributes/k8s_logs_dataset receivers: - kubeletstats - hostmetrics diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/shared/accordion_with_icon.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/shared/accordion_with_icon.tsx index 9301ddb9a78a4..2f18c299bbc56 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/shared/accordion_with_icon.tsx +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/shared/accordion_with_icon.tsx @@ -8,7 +8,6 @@ import React, { type FunctionComponent } from 'react'; import { EuiAccordion, - EuiIcon, EuiTitle, EuiFlexGroup, EuiFlexItem, @@ -18,11 +17,11 @@ import { interface AccordionWithIconProps extends Omit { title: string; - iconType: string; + icon: React.ReactNode; } export const AccordionWithIcon: FunctionComponent = ({ title, - iconType, + icon, children, ...rest }) => { @@ -31,9 +30,7 @@ export const AccordionWithIcon: FunctionComponent = ({ {...rest} buttonContent={ - - - + {icon}

    {title}

    diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/shared/get_started_panel.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/shared/get_started_panel.tsx new file mode 100644 index 0000000000000..d524b2775a427 --- /dev/null +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/shared/get_started_panel.tsx @@ -0,0 +1,112 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + EuiFlexGroup, + EuiFlexItem, + EuiImage, + EuiLink, + EuiSkeletonRectangle, + EuiSpacer, + EuiText, +} from '@elastic/eui'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { DASHBOARD_APP_LOCATOR } from '@kbn/deeplinks-analytics'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { ObservabilityOnboardingContextValue } from '../../../plugin'; + +export function GetStartedPanel({ + integration, + dashboardLinks, + newTab, + isLoading, +}: { + integration: string; + newTab: boolean; + dashboardLinks: Array<{ + id: string; + label: string; + title: string; + }>; + isLoading: boolean; +}) { + const { + services: { http, share }, + } = useKibana(); + + const dashboardLocator = share.url.locators.get(DASHBOARD_APP_LOCATOR); + + return ( + <> + + + {isLoading ? ( + + ) : ( + + )} + + + + + {dashboardLinks.map(({ id, label, title }) => ( + + + +

    {title}

    +
    + + {label} + +
    +
    + ))} +
    +
    +
    + + + + + + {i18n.translate( + 'xpack.observability_onboarding.dataIngestStatus.viewAllAssetsLinkText', + { + defaultMessage: 'View all assets', + } + )} + + ), + }} + /> + + + ); +} diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/shared/logo_icon.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/shared/logo_icon.tsx new file mode 100644 index 0000000000000..6f4eeb1ba71e7 --- /dev/null +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/shared/logo_icon.tsx @@ -0,0 +1,75 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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, EuiIconProps } from '@elastic/eui'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import React from 'react'; + +export type SupportedLogo = + | 'aws' + | 'azure' + | 'docker' + | 'dotnet' + | 'prometheus' + | 'gcp' + | 'java' + | 'javascript' + | 'kubernetes' + | 'nginx' + | 'apache' + | 'system' + | 'opentelemetry'; + +export function isSupportedLogo(logo: string): logo is SupportedLogo { + return [ + 'aws', + 'azure', + 'docker', + 'dotnet', + 'prometheus', + 'gcp', + 'java', + 'javascript', + 'kubernetes', + 'nginx', + 'system', + 'apache', + 'opentelemetry', + ].includes(logo); +} + +function useIconForLogo(logo?: SupportedLogo): string | undefined { + const { + services: { http }, + } = useKibana(); + switch (logo) { + case 'aws': + return 'logoAWS'; + case 'azure': + return 'logoAzure'; + case 'gcp': + return 'logoGCP'; + case 'kubernetes': + return 'logoKubernetes'; + case 'nginx': + return 'logoNginx'; + case 'prometheus': + return 'logoPrometheus'; + case 'docker': + return 'logoDocker'; + default: + return http?.staticAssets.getPluginAssetHref(`${logo}.svg`); + } +} + +export function LogoIcon({ logo, size }: { logo: SupportedLogo; size?: EuiIconProps['size'] }) { + const iconType = useIconForLogo(logo); + if (iconType) { + return ; + } + return null; +} diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/assets/apache.svg b/x-pack/plugins/observability_solution/observability_onboarding/public/assets/apache.svg new file mode 100644 index 0000000000000..384761f64108a --- /dev/null +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/assets/apache.svg @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/x-pack/plugins/observability_solution/observability_onboarding/tsconfig.json b/x-pack/plugins/observability_solution/observability_onboarding/tsconfig.json index 5833bba22a6e4..b60ec81b3c11f 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/tsconfig.json +++ b/x-pack/plugins/observability_solution/observability_onboarding/tsconfig.json @@ -42,7 +42,6 @@ "@kbn/utility-types", "@kbn/spaces-plugin", "@kbn/ebt", - "@kbn/dashboard-plugin", "@kbn/deeplinks-analytics" ], "exclude": [ diff --git a/x-pack/plugins/observability_solution/observability_shared/public/components/profiling/embeddables/embeddable_functions.tsx b/x-pack/plugins/observability_solution/observability_shared/public/components/profiling/embeddables/embeddable_functions.tsx index 813f7c299649e..c4fad57b890ce 100644 --- a/x-pack/plugins/observability_solution/observability_shared/public/components/profiling/embeddables/embeddable_functions.tsx +++ b/x-pack/plugins/observability_solution/observability_shared/public/components/profiling/embeddables/embeddable_functions.tsx @@ -16,18 +16,23 @@ interface Props { isLoading: boolean; rangeFrom: number; rangeTo: number; + height?: string; } export function EmbeddableFunctions(props: Props) { const EmbeddableFunctionsComponent = getProfilingComponent(EMBEDDABLE_FUNCTIONS); + const { height } = props; + const heightSetting = height ? `height: ${height}` : 'min-height: 0'; + return (
    {EmbeddableFunctionsComponent && } diff --git a/x-pack/plugins/observability_solution/profiling/server/types.ts b/x-pack/plugins/observability_solution/profiling/server/types.ts index ef5028b8d311b..78d92b18fdf06 100644 --- a/x-pack/plugins/observability_solution/profiling/server/types.ts +++ b/x-pack/plugins/observability_solution/profiling/server/types.ts @@ -6,7 +6,7 @@ */ import { CustomRequestHandlerContext } from '@kbn/core-http-request-handler-context-server'; -import type { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import type { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import type { ObservabilityPluginSetup } from '@kbn/observability-plugin/server'; import { SpacesPluginStart, SpacesPluginSetup } from '@kbn/spaces-plugin/server'; import { CloudSetup, CloudStart } from '@kbn/cloud-plugin/server'; diff --git a/x-pack/plugins/observability_solution/slo/common/constants.ts b/x-pack/plugins/observability_solution/slo/common/constants.ts index 37558bda23732..0e4c29070ec2c 100644 --- a/x-pack/plugins/observability_solution/slo/common/constants.ts +++ b/x-pack/plugins/observability_solution/slo/common/constants.ts @@ -66,7 +66,6 @@ export const SLO_INDEX_TEMPLATE_PATTERN = `.slo-observability.sli-*`; export const SLO_DESTINATION_INDEX_NAME = `.slo-observability.sli-v${SLO_RESOURCES_VERSION}`; export const SLO_DESTINATION_INDEX_PATTERN = `.slo-observability.sli-v${SLO_RESOURCES_VERSION_MAJOR}*`; -export const SLO_INGEST_PIPELINE_NAME = `.slo-observability.sli.pipeline-v${SLO_RESOURCES_VERSION}`; export const SLO_INGEST_PIPELINE_INDEX_NAME_PREFIX = `.slo-observability.sli-v${SLO_RESOURCES_VERSION}.`; export const SLO_SUMMARY_COMPONENT_TEMPLATE_MAPPINGS_NAME = '.slo-observability.summary-mappings'; @@ -87,6 +86,9 @@ export const DEFAULT_SLO_GROUPS_PAGE_SIZE = 25; export const getSLOSummaryTransformId = (sloId: string, sloRevision: number) => `slo-summary-${sloId}-${sloRevision}`; +export const getSLOPipelineId = (sloId: string, sloRevision: number) => + `.slo-observability.sli.pipeline-${sloId}-${sloRevision}`; + export const getSLOSummaryPipelineId = (sloId: string, sloRevision: number) => `.slo-observability.summary.pipeline-${sloId}-${sloRevision}`; diff --git a/x-pack/plugins/observability_solution/slo/public/components/slo/delete_confirmation_modal/slo_delete_confirmation_modal.tsx b/x-pack/plugins/observability_solution/slo/public/components/slo/delete_confirmation_modal/slo_delete_confirmation_modal.tsx index 9969c7c714e5f..c5dcf745e25de 100644 --- a/x-pack/plugins/observability_solution/slo/public/components/slo/delete_confirmation_modal/slo_delete_confirmation_modal.tsx +++ b/x-pack/plugins/observability_solution/slo/public/components/slo/delete_confirmation_modal/slo_delete_confirmation_modal.tsx @@ -116,8 +116,7 @@ export function SloDeleteModal({ slo, onCancel, onSuccess }: Props) { > )} diff --git a/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_slo_groups.ts b/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_slo_groups.ts index dd52db476b2f3..f7cdfbed28f3f 100644 --- a/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_slo_groups.ts +++ b/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_slo_groups.ts @@ -98,7 +98,7 @@ export function useFetchSloGroups({ }), queryFn: async ({ signal }) => { const response = await http.get( - '/internal/api/observability/slos/_groups', + '/internal/observability/slos/_groups', { query: { ...(page && { page }), diff --git a/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_slo_inspect.ts b/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_slo_inspect.ts index 0bd671cf74776..51308b23b3300 100644 --- a/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_slo_inspect.ts +++ b/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_slo_inspect.ts @@ -12,7 +12,8 @@ import { useKibana } from '../utils/kibana_react'; interface SLOInspectResponse { slo: SLODefinitionResponse; - pipeline: Record; + rollUpPipeline: Record; + summaryPipeline: Record; rollUpTransform: TransformPutTransformRequest; summaryTransform: TransformPutTransformRequest; temporaryDoc: Record; @@ -29,7 +30,7 @@ export function useFetchSloInspect(slo: CreateSLOInput, shouldInspect: boolean) try { const body = JSON.stringify(slo); const response = await http.post( - '/internal/api/observability/slos/_inspect', + '/internal/observability/slos/_inspect', { body, signal, diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/common/slo_inspect/slo_inspect.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/common/slo_inspect/slo_inspect.tsx index 9399492f0ad28..18d0d966c1ac0 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/common/slo_inspect/slo_inspect.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/common/slo_inspect/slo_inspect.tsx @@ -65,16 +65,27 @@ function SLOInspect({ slo, disabled }: Props) { isFlyoutVisible && isFormValid ); - const { data: pipeLineUrl } = useFetcher(async () => { + const { data: summaryPipelineUrl } = useFetcher(async () => { const ingestPipeLocator = share.url.locators.get( INGEST_PIPELINES_APP_LOCATOR ); - const ingestPipeLineId = inspectSloData?.pipeline?.id; + const ingestPipelineId = inspectSloData?.summaryPipeline?.id; return ingestPipeLocator?.getUrl({ - pipelineId: ingestPipeLineId, + pipelineId: ingestPipelineId, page: INGEST_PIPELINES_PAGES.LIST, }); - }, [inspectSloData?.pipeline?.id, share.url.locators]); + }, [inspectSloData?.summaryPipeline?.id, share.url.locators]); + + const { data: rollUpPipelineUrl } = useFetcher(async () => { + const ingestPipeLocator = share.url.locators.get( + INGEST_PIPELINES_APP_LOCATOR + ); + const ingestPipelineId = inspectSloData?.rollUpPipeline?.id; + return ingestPipeLocator?.getUrl({ + pipelineId: ingestPipelineId, + page: INGEST_PIPELINES_PAGES.LIST, + }); + }, [inspectSloData?.rollUpPipeline?.id, share.url.locators]); const closeFlyout = () => { setIsFlyoutVisible(false); @@ -154,19 +165,36 @@ function SLOInspect({ slo, disabled }: Props) { + } + json={inspectSloData.rollUpPipeline} + /> + + + } - json={inspectSloData.pipeline} + json={inspectSloData.summaryPipeline} /> diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_fetch_suggestions.ts b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_fetch_suggestions.ts index 7e66bc954f23c..ff9ebffa72f56 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_fetch_suggestions.ts +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_fetch_suggestions.ts @@ -17,7 +17,7 @@ export function useFetchSLOSuggestions() { queryFn: async ({ signal }) => { try { return await http.get( - '/internal/api/observability/slos/suggestions', + '/internal/observability/slos/suggestions', { signal, } diff --git a/x-pack/plugins/observability_solution/slo/server/assets/ingest_templates/slo_pipeline_template.ts b/x-pack/plugins/observability_solution/slo/server/assets/ingest_templates/slo_pipeline_template.ts index 4fe244e4f28a2..03c03a8c6447c 100644 --- a/x-pack/plugins/observability_solution/slo/server/assets/ingest_templates/slo_pipeline_template.ts +++ b/x-pack/plugins/observability_solution/slo/server/assets/ingest_templates/slo_pipeline_template.ts @@ -5,11 +5,16 @@ * 2.0. */ -import { SLO_RESOURCES_VERSION } from '../../../common/constants'; +import { + getSLOPipelineId, + SLO_INGEST_PIPELINE_INDEX_NAME_PREFIX, + SLO_RESOURCES_VERSION, +} from '../../../common/constants'; +import { SLODefinition } from '../../domain/models'; -export const getSLOPipelineTemplate = (id: string, indexNamePrefix: string) => ({ - id, - description: 'Ingest pipeline for SLO rollup data', +export const getSLOPipelineTemplate = (slo: SLODefinition) => ({ + id: getSLOPipelineId(slo.id, slo.revision), + description: `Ingest pipeline for SLO rollup data [id: ${slo.id}, revision: ${slo.revision}]`, processors: [ { set: { @@ -17,10 +22,22 @@ export const getSLOPipelineTemplate = (id: string, indexNamePrefix: string) => ( value: '{{{_ingest.timestamp}}}', }, }, + { + set: { + field: 'slo.id', + value: slo.id, + }, + }, + { + set: { + field: 'slo.revision', + value: slo.revision, + }, + }, { date_index_name: { field: '@timestamp', - index_name_prefix: indexNamePrefix, + index_name_prefix: SLO_INGEST_PIPELINE_INDEX_NAME_PREFIX, date_rounding: 'M', date_formats: ['UNIX_MS', 'ISO8601', "yyyy-MM-dd'T'HH:mm:ss.SSSXX"], }, diff --git a/x-pack/plugins/observability_solution/slo/server/domain/services/validate_slo.ts b/x-pack/plugins/observability_solution/slo/server/domain/services/validate_slo.ts index fadf4ea08e6ea..410c9e7c9d29e 100644 --- a/x-pack/plugins/observability_solution/slo/server/domain/services/validate_slo.ts +++ b/x-pack/plugins/observability_solution/slo/server/domain/services/validate_slo.ts @@ -76,7 +76,7 @@ function validateSettings(slo: SLODefinition) { function isValidId(id: string): boolean { const MIN_ID_LENGTH = 8; - const MAX_ID_LENGTH = 36; + const MAX_ID_LENGTH = 48; return MIN_ID_LENGTH <= id.length && id.length <= MAX_ID_LENGTH; } diff --git a/x-pack/plugins/observability_solution/slo/server/plugin.ts b/x-pack/plugins/observability_solution/slo/server/plugin.ts index 9c701a3477485..9c986a1f5fa8d 100644 --- a/x-pack/plugins/observability_solution/slo/server/plugin.ts +++ b/x-pack/plugins/observability_solution/slo/server/plugin.ts @@ -16,7 +16,7 @@ import { SavedObjectsClient, } from '@kbn/core/server'; import { PluginSetupContract, PluginStartContract } from '@kbn/alerting-plugin/server'; -import { PluginSetupContract as FeaturesSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { RuleRegistryPluginSetupContract, RuleRegistryPluginStartContract, @@ -49,7 +49,7 @@ export interface PluginSetup { alerting: PluginSetupContract; ruleRegistry: RuleRegistryPluginSetupContract; share: SharePluginSetup; - features: FeaturesSetup; + features: FeaturesPluginSetup; taskManager: TaskManagerSetupContract; spaces?: SpacesPluginSetup; cloud?: CloudSetup; diff --git a/x-pack/plugins/observability_solution/slo/server/routes/slo/route.ts b/x-pack/plugins/observability_solution/slo/server/routes/slo/route.ts index 1f4c3ee2e3bb3..3a06e653c8159 100644 --- a/x-pack/plugins/observability_solution/slo/server/routes/slo/route.ts +++ b/x-pack/plugins/observability_solution/slo/server/routes/slo/route.ts @@ -141,10 +141,10 @@ const createSLORoute = createSloServerRoute({ }); const inspectSLORoute = createSloServerRoute({ - endpoint: 'POST /internal/api/observability/slos/_inspect 2023-10-31', + endpoint: 'POST /internal/observability/slos/_inspect', options: { tags: ['access:slo_write'], - access: 'public', + access: 'internal', }, params: createSLOParamsSchema, handler: async ({ context, params, logger, dependencies, request }) => { @@ -455,7 +455,7 @@ const findSLORoute = createSloServerRoute({ }); const findSLOGroupsRoute = createSloServerRoute({ - endpoint: 'GET /internal/api/observability/slos/_groups', + endpoint: 'GET /internal/observability/slos/_groups', options: { tags: ['access:slo_read'], access: 'internal', @@ -475,7 +475,7 @@ const findSLOGroupsRoute = createSloServerRoute({ }); const getSLOSuggestionsRoute = createSloServerRoute({ - endpoint: 'GET /internal/api/observability/slos/suggestions', + endpoint: 'GET /internal/observability/slos/suggestions', options: { tags: ['access:slo_read'], access: 'internal', @@ -528,6 +528,7 @@ const fetchHistoricalSummary = createSloServerRoute({ endpoint: 'POST /internal/observability/slos/_historical_summary', options: { tags: ['access:slo_read'], + access: 'internal', }, params: fetchHistoricalSummaryParamsSchema, handler: async ({ context, params, logger }) => { diff --git a/x-pack/plugins/observability_solution/slo/server/services/__snapshots__/create_slo.test.ts.snap b/x-pack/plugins/observability_solution/slo/server/services/__snapshots__/create_slo.test.ts.snap index 8416373c460bf..d516bafa84393 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/__snapshots__/create_slo.test.ts.snap +++ b/x-pack/plugins/observability_solution/slo/server/services/__snapshots__/create_slo.test.ts.snap @@ -4,253 +4,86 @@ exports[`CreateSLO happy path calls the expected services 1`] = ` Array [ Object { "_meta": Object { - "description": "Ingest pipeline for SLO summary data [id: unique-id, revision: 1]", + "description": "Ingest pipeline for SLO rollup data", "managed": true, "managed_by": "observability", "version": 3.3, }, - "description": "Ingest pipeline for SLO summary data [id: unique-id, revision: 1]", - "id": ".slo-observability.summary.pipeline-unique-id-1", + "description": "Ingest pipeline for SLO rollup data [id: unique-id, revision: 1]", + "id": ".slo-observability.sli.pipeline-unique-id-1", "processors": Array [ Object { "set": Object { - "description": "Set errorBudgetEstimated field", - "field": "errorBudgetEstimated", - "value": false, - }, - }, - Object { - "set": Object { - "description": "Set isTempDoc field", - "field": "isTempDoc", - "value": false, - }, - }, - Object { - "set": Object { - "description": "Set groupBy field", - "field": "slo.groupBy", - "value": "*", - }, - }, - Object { - "set": Object { - "description": "Set name field", - "field": "slo.name", - "value": "irrelevant", - }, - }, - Object { - "set": Object { - "description": "Set description field", - "field": "slo.description", - "value": "irrelevant", - }, - }, - Object { - "set": Object { - "description": "Set tags field", - "field": "slo.tags", - "value": Array [], - }, - }, - Object { - "set": Object { - "description": "Set indicator.type field", - "field": "slo.indicator.type", - "value": "sli.apm.transactionErrorRate", - }, - }, - Object { - "set": Object { - "description": "Set budgetingMethod field", - "field": "slo.budgetingMethod", - "value": "occurrences", - }, - }, - Object { - "set": Object { - "description": "Set timeWindow.duration field", - "field": "slo.timeWindow.duration", - "value": "7d", - }, - }, - Object { - "set": Object { - "description": "Set timeWindow.type field", - "field": "slo.timeWindow.type", - "value": "rolling", - }, - }, - Object { - "set": Object { - "description": "Set objective.target field", - "field": "slo.objective.target", - "value": 0.99, - }, - }, - Object { - "set": Object { - "description": "if 'statusCode == 0', set status to NO_DATA", - "field": "status", - "if": "ctx.statusCode == 0", - "value": "NO_DATA", - }, - }, - Object { - "set": Object { - "description": "if 'statusCode == 1', set statusLabel to VIOLATED", - "field": "status", - "if": "ctx.statusCode == 1", - "value": "VIOLATED", - }, - }, - Object { - "set": Object { - "description": "if 'statusCode == 2', set status to DEGRADING", - "field": "status", - "if": "ctx.statusCode == 2", - "value": "DEGRADING", - }, - }, - Object { - "set": Object { - "description": "if 'statusCode == 4', set status to HEALTHY", - "field": "status", - "if": "ctx.statusCode == 4", - "value": "HEALTHY", - }, - }, - Object { - "set": Object { - "field": "summaryUpdatedAt", + "field": "event.ingested", "value": "{{{_ingest.timestamp}}}", }, }, Object { "set": Object { - "field": "spaceId", - "value": "some-space", + "field": "slo.id", + "value": "unique-id", }, }, Object { "set": Object { - "description": "Store the indicator params", - "field": "slo.indicator.params", - "ignore_failure": true, - "value": Object { - "environment": "irrelevant", - "index": "metrics-apm*", - "service": "irrelevant", - "transactionName": "irrelevant", - "transactionType": "irrelevant", - }, + "field": "slo.revision", + "value": 1, }, }, Object { - "set": Object { - "field": "slo.createdAt", - "value": 2024-01-01T00:00:00.000Z, - }, - }, - Object { - "set": Object { - "field": "slo.updatedAt", - "value": 2024-01-01T00:00:00.000Z, - }, - }, - Object { - "set": Object { - "field": "kibanaUrl", - "ignore_failure": true, - "value": "http://myhost.com/mock-server-basepath", + "date_index_name": Object { + "date_formats": Array [ + "UNIX_MS", + "ISO8601", + "yyyy-MM-dd'T'HH:mm:ss.SSSXX", + ], + "date_rounding": "M", + "field": "@timestamp", + "index_name_prefix": ".slo-observability.sli-v3.3.", }, }, Object { "script": Object { - "description": "Computes the last five minute burn rate value", - "lang": "painless", - "params": Object { - "isTimeslice": false, - "totalSlicesInRange": 0, - }, - "source": "def totalEvents = ctx[\\"fiveMinuteBurnRate\\"][\\"totalEvents\\"]; - def goodEvents = ctx[\\"fiveMinuteBurnRate\\"][\\"goodEvents\\"]; - def errorBudgetInitial = ctx[\\"errorBudgetInitial\\"]; + "description": "Generated the instanceId field for SLO rollup data", + "source": " + // This function will recursively collect all the values of a HashMap of HashMaps + Collection collectValues(HashMap subject) { + Collection values = new ArrayList(); + // Iterate through the values + for(Object value: subject.values()) { + // If the value is a HashMap, recurse + if (value instanceof HashMap) { + values.addAll(collectValues((HashMap) value)); + } else { + values.add(String.valueOf(value)); + } + } + return values; + } - if (totalEvents == null || totalEvents == 0) { - ctx[\\"fiveMinuteBurnRate\\"][\\"value\\"] = 0.0; - return; - } - - def totalSlicesInRange = params[\\"totalSlicesInRange\\"]; - def isTimeslice = params[\\"isTimeslice\\"]; - if (isTimeslice && totalSlicesInRange > 0) { - def badEvents = (double)totalEvents - (double)goodEvents; - def sliValue = 1.0 - (badEvents / (double)totalSlicesInRange); - ctx[\\"fiveMinuteBurnRate\\"][\\"value\\"] = (1.0 - sliValue) / errorBudgetInitial; - } else { - def sliValue = (double)goodEvents / (double)totalEvents; - ctx[\\"fiveMinuteBurnRate\\"][\\"value\\"] = (1.0 - sliValue) / errorBudgetInitial; - }", - }, - }, - Object { - "script": Object { - "description": "Computes the last hour burn rate value", - "lang": "painless", - "params": Object { - "isTimeslice": false, - "totalSlicesInRange": 0, - }, - "source": "def totalEvents = ctx[\\"oneHourBurnRate\\"][\\"totalEvents\\"]; - def goodEvents = ctx[\\"oneHourBurnRate\\"][\\"goodEvents\\"]; - def errorBudgetInitial = ctx[\\"errorBudgetInitial\\"]; + // Create the string builder + StringBuilder instanceId = new StringBuilder(); - if (totalEvents == null || totalEvents == 0) { - ctx[\\"oneHourBurnRate\\"][\\"value\\"] = 0.0; - return; - } + if (ctx[\\"slo\\"][\\"groupings\\"] == null) { + ctx[\\"slo\\"][\\"instanceId\\"] = \\"*\\"; + } else { + // Get the values as a collection + Collection values = collectValues(ctx[\\"slo\\"][\\"groupings\\"]); - def totalSlicesInRange = params[\\"totalSlicesInRange\\"]; - def isTimeslice = params[\\"isTimeslice\\"]; - if (isTimeslice && totalSlicesInRange > 0) { - def badEvents = (double)totalEvents - (double)goodEvents; - def sliValue = 1.0 - (badEvents / (double)totalSlicesInRange); - ctx[\\"oneHourBurnRate\\"][\\"value\\"] = (1.0 - sliValue) / errorBudgetInitial; - } else { - def sliValue = (double)goodEvents / (double)totalEvents; - ctx[\\"oneHourBurnRate\\"][\\"value\\"] = (1.0 - sliValue) / errorBudgetInitial; - }", - }, - }, - Object { - "script": Object { - "description": "Computes the last day burn rate value", - "lang": "painless", - "params": Object { - "isTimeslice": false, - "totalSlicesInRange": 0, - }, - "source": "def totalEvents = ctx[\\"oneDayBurnRate\\"][\\"totalEvents\\"]; - def goodEvents = ctx[\\"oneDayBurnRate\\"][\\"goodEvents\\"]; - def errorBudgetInitial = ctx[\\"errorBudgetInitial\\"]; + // Convert to a list and sort + List sortedValues = new ArrayList(values); + Collections.sort(sortedValues); - if (totalEvents == null || totalEvents == 0) { - ctx[\\"oneDayBurnRate\\"][\\"value\\"] = 0.0; - return; - } + // Create comma delimited string + for(String instanceValue: sortedValues) { + instanceId.append(instanceValue); + instanceId.append(\\",\\"); + } - def totalSlicesInRange = params[\\"totalSlicesInRange\\"]; - def isTimeslice = params[\\"isTimeslice\\"]; - if (isTimeslice && totalSlicesInRange > 0) { - def badEvents = (double)totalEvents - (double)goodEvents; - def sliValue = 1.0 - (badEvents / (double)totalSlicesInRange); - ctx[\\"oneDayBurnRate\\"][\\"value\\"] = (1.0 - sliValue) / errorBudgetInitial; - } else { - def sliValue = (double)goodEvents / (double)totalEvents; - ctx[\\"oneDayBurnRate\\"][\\"value\\"] = (1.0 - sliValue) / errorBudgetInitial; - }", + // Assign the slo.instanceId + ctx[\\"slo\\"][\\"instanceId\\"] = instanceId.length() > 0 ? instanceId.substring(0, instanceId.length() - 1) : \\"*\\"; + } + ", }, }, ], diff --git a/x-pack/plugins/observability_solution/slo/server/services/__snapshots__/delete_slo.test.ts.snap b/x-pack/plugins/observability_solution/slo/server/services/__snapshots__/delete_slo.test.ts.snap index 3edfb0cd194b0..598e66449ccac 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/__snapshots__/delete_slo.test.ts.snap +++ b/x-pack/plugins/observability_solution/slo/server/services/__snapshots__/delete_slo.test.ts.snap @@ -83,6 +83,16 @@ exports[`DeleteSLO happy path removes all resources associatde to the slo 5`] = exports[`DeleteSLO happy path removes all resources associatde to the slo 6`] = ` [MockFunction] { "calls": Array [ + Array [ + Object { + "id": ".slo-observability.sli.pipeline-irrelevant-1", + }, + Object { + "ignore": Array [ + 404, + ], + }, + ], Array [ Object { "id": ".slo-observability.summary.pipeline-irrelevant-1", @@ -99,6 +109,10 @@ exports[`DeleteSLO happy path removes all resources associatde to the slo 6`] = "type": "return", "value": Promise {}, }, + Object { + "type": "return", + "value": Promise {}, + }, ], } `; diff --git a/x-pack/plugins/observability_solution/slo/server/services/__snapshots__/reset_slo.test.ts.snap b/x-pack/plugins/observability_solution/slo/server/services/__snapshots__/reset_slo.test.ts.snap index 721402bc88961..8c20bec0d6424 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/__snapshots__/reset_slo.test.ts.snap +++ b/x-pack/plugins/observability_solution/slo/server/services/__snapshots__/reset_slo.test.ts.snap @@ -197,6 +197,94 @@ exports[`ResetSLO resets all associated resources 7`] = ` exports[`ResetSLO resets all associated resources 8`] = ` [MockFunction] { "calls": Array [ + Array [ + Object { + "_meta": Object { + "description": "Ingest pipeline for SLO rollup data", + "managed": true, + "managed_by": "observability", + "version": 3.3, + }, + "description": "Ingest pipeline for SLO rollup data [id: irrelevant, revision: 1]", + "id": ".slo-observability.sli.pipeline-irrelevant-1", + "processors": Array [ + Object { + "set": Object { + "field": "event.ingested", + "value": "{{{_ingest.timestamp}}}", + }, + }, + Object { + "set": Object { + "field": "slo.id", + "value": "irrelevant", + }, + }, + Object { + "set": Object { + "field": "slo.revision", + "value": 1, + }, + }, + Object { + "date_index_name": Object { + "date_formats": Array [ + "UNIX_MS", + "ISO8601", + "yyyy-MM-dd'T'HH:mm:ss.SSSXX", + ], + "date_rounding": "M", + "field": "@timestamp", + "index_name_prefix": ".slo-observability.sli-v3.3.", + }, + }, + Object { + "script": Object { + "description": "Generated the instanceId field for SLO rollup data", + "source": " + // This function will recursively collect all the values of a HashMap of HashMaps + Collection collectValues(HashMap subject) { + Collection values = new ArrayList(); + // Iterate through the values + for(Object value: subject.values()) { + // If the value is a HashMap, recurse + if (value instanceof HashMap) { + values.addAll(collectValues((HashMap) value)); + } else { + values.add(String.valueOf(value)); + } + } + return values; + } + + // Create the string builder + StringBuilder instanceId = new StringBuilder(); + + if (ctx[\\"slo\\"][\\"groupings\\"] == null) { + ctx[\\"slo\\"][\\"instanceId\\"] = \\"*\\"; + } else { + // Get the values as a collection + Collection values = collectValues(ctx[\\"slo\\"][\\"groupings\\"]); + + // Convert to a list and sort + List sortedValues = new ArrayList(values); + Collections.sort(sortedValues); + + // Create comma delimited string + for(String instanceValue: sortedValues) { + instanceId.append(instanceValue); + instanceId.append(\\",\\"); + } + + // Assign the slo.instanceId + ctx[\\"slo\\"][\\"instanceId\\"] = instanceId.length() > 0 ? instanceId.substring(0, instanceId.length() - 1) : \\"*\\"; + } + ", + }, + }, + ], + }, + ], Array [ Object { "_meta": Object { @@ -462,6 +550,10 @@ exports[`ResetSLO resets all associated resources 8`] = ` "type": "return", "value": Promise {}, }, + Object { + "type": "return", + "value": Promise {}, + }, ], } `; diff --git a/x-pack/plugins/observability_solution/slo/server/services/create_slo.test.ts b/x-pack/plugins/observability_solution/slo/server/services/create_slo.test.ts index 7b45b321f4057..1acc263a2d655 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/create_slo.test.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/create_slo.test.ts @@ -165,12 +165,12 @@ describe('CreateSLO', () => { ); expect(mockRepository.deleteById).toHaveBeenCalled(); + expect(mockEsClient.ingest.deletePipeline).toHaveBeenCalledTimes(1); expect(mockSummaryTransformManager.stop).not.toHaveBeenCalled(); expect(mockSummaryTransformManager.uninstall).not.toHaveBeenCalled(); expect(mockTransformManager.stop).not.toHaveBeenCalled(); expect(mockTransformManager.uninstall).not.toHaveBeenCalled(); - expect(mockEsClient.ingest.deletePipeline).not.toHaveBeenCalled(); }); it('rollbacks completed operations when summary transform start fails', async () => { @@ -186,7 +186,7 @@ describe('CreateSLO', () => { expect(mockRepository.deleteById).toHaveBeenCalled(); expect(mockTransformManager.stop).toHaveBeenCalled(); expect(mockTransformManager.uninstall).toHaveBeenCalled(); - expect(mockEsClient.ingest.deletePipeline).toHaveBeenCalled(); + expect(mockEsClient.ingest.deletePipeline).toHaveBeenCalledTimes(2); expect(mockSummaryTransformManager.uninstall).toHaveBeenCalled(); expect(mockSummaryTransformManager.stop).not.toHaveBeenCalled(); @@ -203,7 +203,7 @@ describe('CreateSLO', () => { expect(mockRepository.deleteById).toHaveBeenCalled(); expect(mockTransformManager.stop).toHaveBeenCalled(); expect(mockTransformManager.uninstall).toHaveBeenCalled(); - expect(mockEsClient.ingest.deletePipeline).toHaveBeenCalled(); + expect(mockEsClient.ingest.deletePipeline).toHaveBeenCalledTimes(2); expect(mockSummaryTransformManager.stop).toHaveBeenCalled(); expect(mockSummaryTransformManager.uninstall).toHaveBeenCalled(); }); diff --git a/x-pack/plugins/observability_solution/slo/server/services/create_slo.ts b/x-pack/plugins/observability_solution/slo/server/services/create_slo.ts index 4d2229ef7ba64..f3abb8554f3dd 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/create_slo.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/create_slo.ts @@ -11,12 +11,14 @@ import { ALL_VALUE, CreateSLOParams, CreateSLOResponse } from '@kbn/slo-schema'; import { asyncForEach } from '@kbn/std'; import { v4 as uuidv4 } from 'uuid'; import { + getSLOPipelineId, getSLOSummaryPipelineId, getSLOSummaryTransformId, getSLOTransformId, SLO_MODEL_VERSION, SLO_SUMMARY_TEMP_INDEX_NAME, } from '../../common/constants'; +import { getSLOPipelineTemplate } from '../assets/ingest_templates/slo_pipeline_template'; import { getSLOSummaryPipelineTemplate } from '../assets/ingest_templates/slo_summary_pipeline_template'; import { Duration, DurationUnit, SLODefinition } from '../domain/models'; import { validateSLO } from '../domain/services'; @@ -50,6 +52,17 @@ export class CreateSLO { const rollupTransformId = getSLOTransformId(slo.id, slo.revision); const summaryTransformId = getSLOSummaryTransformId(slo.id, slo.revision); try { + await retryTransientEsErrors( + () => this.esClient.ingest.putPipeline(getSLOPipelineTemplate(slo)), + { logger: this.logger } + ); + rollbackOperations.push(() => + this.esClient.ingest.deletePipeline( + { id: getSLOPipelineId(slo.id, slo.revision) }, + { ignore: [404] } + ) + ); + await this.transformManager.install(slo); rollbackOperations.push(() => this.transformManager.uninstall(rollupTransformId)); @@ -111,7 +124,8 @@ export class CreateSLO { public async inspect(params: CreateSLOParams): Promise<{ slo: CreateSLOParams; - pipeline: Record; + rollUpPipeline: Record; + summaryPipeline: Record; rollUpTransform: TransformPutTransformRequest; summaryTransform: TransformPutTransformRequest; temporaryDoc: Record; @@ -122,13 +136,15 @@ export class CreateSLO { validateSLO(slo); const rollUpTransform = await this.transformManager.inspect(slo); - const pipeline = getSLOSummaryPipelineTemplate(slo, this.spaceId, this.basePath); + const rollUpPipeline = getSLOPipelineTemplate(slo); + const summaryPipeline = getSLOSummaryPipelineTemplate(slo, this.spaceId, this.basePath); const summaryTransform = await this.summaryTransformManager.inspect(slo); const temporaryDoc = createTempSummaryDocument(slo, this.spaceId, this.basePath); return { slo, - pipeline, + rollUpPipeline, + summaryPipeline, temporaryDoc, summaryTransform, rollUpTransform, diff --git a/x-pack/plugins/observability_solution/slo/server/services/delete_slo.ts b/x-pack/plugins/observability_solution/slo/server/services/delete_slo.ts index fa6652dbb30cf..9bd64727e286b 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/delete_slo.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/delete_slo.ts @@ -8,6 +8,7 @@ import { RulesClientApi } from '@kbn/alerting-plugin/server/types'; import { ElasticsearchClient } from '@kbn/core/server'; import { + getSLOPipelineId, getSLOSummaryPipelineId, getSLOSummaryTransformId, getSLOTransformId, @@ -38,6 +39,13 @@ export class DeleteSLO { await this.transformManager.stop(rollupTransformId); await this.transformManager.uninstall(rollupTransformId); + await retryTransientEsErrors(() => + this.esClient.ingest.deletePipeline( + { id: getSLOPipelineId(slo.id, slo.revision) }, + { ignore: [404] } + ) + ); + await retryTransientEsErrors(() => this.esClient.ingest.deletePipeline( { id: getSLOSummaryPipelineId(slo.id, slo.revision) }, diff --git a/x-pack/plugins/observability_solution/slo/server/services/reset_slo.ts b/x-pack/plugins/observability_solution/slo/server/services/reset_slo.ts index f93fce029913f..3eb5dc6d89672 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/reset_slo.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/reset_slo.ts @@ -8,6 +8,7 @@ import { ElasticsearchClient, IBasePath, Logger } from '@kbn/core/server'; import { resetSLOResponseSchema } from '@kbn/slo-schema'; import { + getSLOPipelineId, getSLOSummaryPipelineId, getSLOSummaryTransformId, getSLOTransformId, @@ -16,6 +17,7 @@ import { SLO_SUMMARY_DESTINATION_INDEX_PATTERN, SLO_SUMMARY_TEMP_INDEX_NAME, } from '../../common/constants'; +import { getSLOPipelineTemplate } from '../assets/ingest_templates/slo_pipeline_template'; import { getSLOSummaryPipelineTemplate } from '../assets/ingest_templates/slo_summary_pipeline_template'; import { retryTransientEsErrors } from '../utils/retry'; import { SLORepository } from './slo_repository'; @@ -47,8 +49,14 @@ export class ResetSLO { await Promise.all([this.deleteRollupData(slo.id), this.deleteSummaryData(slo.id)]); try { + await retryTransientEsErrors( + () => this.esClient.ingest.putPipeline(getSLOPipelineTemplate(slo)), + { logger: this.logger } + ); + await this.transformManager.install(slo); await this.transformManager.start(rollupTransformId); + await retryTransientEsErrors( () => this.esClient.ingest.putPipeline( @@ -84,6 +92,11 @@ export class ResetSLO { { ignore: [404] } ); + await this.esClient.ingest.deletePipeline( + { id: getSLOPipelineId(slo.id, slo.revision) }, + { ignore: [404] } + ); + throw err; } diff --git a/x-pack/plugins/observability_solution/slo/server/services/resource_installer.test.ts b/x-pack/plugins/observability_solution/slo/server/services/resource_installer.test.ts index 55f5db79680ba..3f72ace983d20 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/resource_installer.test.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/resource_installer.test.ts @@ -5,18 +5,16 @@ * 2.0. */ -import type { IngestPipeline } from '@elastic/elasticsearch/lib/api/types'; import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; import { loggerMock } from '@kbn/logging-mocks'; import { SLO_COMPONENT_TEMPLATE_MAPPINGS_NAME, SLO_COMPONENT_TEMPLATE_SETTINGS_NAME, SLO_INDEX_TEMPLATE_NAME, - SLO_INGEST_PIPELINE_NAME, + SLO_RESOURCES_VERSION, SLO_SUMMARY_COMPONENT_TEMPLATE_MAPPINGS_NAME, SLO_SUMMARY_COMPONENT_TEMPLATE_SETTINGS_NAME, SLO_SUMMARY_INDEX_TEMPLATE_NAME, - SLO_RESOURCES_VERSION, } from '../../common/constants'; import { DefaultResourceInstaller } from './resource_installer'; @@ -52,13 +50,7 @@ describe('resourceInstaller', () => { }, ], }); - mockClusterClient.ingest.getPipeline.mockResponse({ - [SLO_INGEST_PIPELINE_NAME]: { - _meta: { - version: 2, - }, - } as IngestPipeline, - }); + const installer = new DefaultResourceInstaller(mockClusterClient, loggerMock.create()); await installer.ensureCommonResourcesInstalled(); @@ -89,12 +81,6 @@ describe('resourceInstaller', () => { 2, expect.objectContaining({ name: SLO_SUMMARY_INDEX_TEMPLATE_NAME }) ); - - expect(mockClusterClient.ingest.putPipeline).toHaveBeenCalledTimes(1); - expect(mockClusterClient.ingest.putPipeline).toHaveBeenNthCalledWith( - 1, - expect.objectContaining({ id: SLO_INGEST_PIPELINE_NAME }) - ); }); it('does not install the common resources when there is a version match', async () => { @@ -128,20 +114,12 @@ describe('resourceInstaller', () => { }, ], }); - mockClusterClient.ingest.getPipeline.mockResponse({ - [SLO_INGEST_PIPELINE_NAME]: { - _meta: { - version: SLO_RESOURCES_VERSION, - }, - } as IngestPipeline, - }); + const installer = new DefaultResourceInstaller(mockClusterClient, loggerMock.create()); await installer.ensureCommonResourcesInstalled(); expect(mockClusterClient.cluster.putComponentTemplate).not.toHaveBeenCalled(); expect(mockClusterClient.indices.putIndexTemplate).not.toHaveBeenCalled(); - - expect(mockClusterClient.ingest.putPipeline).not.toHaveBeenCalled(); }); }); diff --git a/x-pack/plugins/observability_solution/slo/server/services/resource_installer.ts b/x-pack/plugins/observability_solution/slo/server/services/resource_installer.ts index c7ae180100dce..b81fbe183c4ff 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/resource_installer.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/resource_installer.ts @@ -8,9 +8,6 @@ import type { ClusterPutComponentTemplateRequest, IndicesPutIndexTemplateRequest, - IngestPutPipelineRequest, - IngestPipeline, - Metadata, } from '@elastic/elasticsearch/lib/api/types'; import type { ElasticsearchClient, Logger } from '@kbn/core/server'; import { getSLOMappingsTemplate } from '../assets/component_templates/slo_mappings_template'; @@ -23,8 +20,6 @@ import { SLO_DESTINATION_INDEX_NAME, SLO_INDEX_TEMPLATE_NAME, SLO_INDEX_TEMPLATE_PATTERN, - SLO_INGEST_PIPELINE_INDEX_NAME_PREFIX, - SLO_INGEST_PIPELINE_NAME, SLO_SUMMARY_COMPONENT_TEMPLATE_MAPPINGS_NAME, SLO_SUMMARY_COMPONENT_TEMPLATE_SETTINGS_NAME, SLO_SUMMARY_DESTINATION_INDEX_NAME, @@ -34,15 +29,13 @@ import { } from '../../common/constants'; import { getSLOIndexTemplate } from '../assets/index_templates/slo_index_templates'; import { getSLOSummaryIndexTemplate } from '../assets/index_templates/slo_summary_index_templates'; -import { getSLOPipelineTemplate } from '../assets/ingest_templates/slo_pipeline_template'; + import { retryTransientEsErrors } from '../utils/retry'; export interface ResourceInstaller { ensureCommonResourcesInstalled(): Promise; } -type IngestPipelineWithMetadata = IngestPipeline & { _meta?: Metadata }; - export class DefaultResourceInstaller implements ResourceInstaller { constructor(private esClient: ElasticsearchClient, private logger: Logger) {} @@ -85,10 +78,6 @@ export class DefaultResourceInstaller implements ResourceInstaller { await this.createIndex(SLO_DESTINATION_INDEX_NAME); await this.createIndex(SLO_SUMMARY_DESTINATION_INDEX_NAME); await this.createIndex(SLO_SUMMARY_TEMP_INDEX_NAME); - - await this.createOrUpdateIngestPipelineTemplate( - getSLOPipelineTemplate(SLO_INGEST_PIPELINE_NAME, SLO_INGEST_PIPELINE_INDEX_NAME_PREFIX) - ); } catch (err) { this.logger.error(`Error installing resources shared for SLO: ${err.message}`); throw err; @@ -124,20 +113,6 @@ export class DefaultResourceInstaller implements ResourceInstaller { } } - private async createOrUpdateIngestPipelineTemplate(template: IngestPutPipelineRequest) { - const currentVersion = await fetchIngestPipelineVersion( - template.id, - this.logger, - this.esClient - ); - if (template._meta?.version && currentVersion === template._meta.version) { - this.logger.info(`SLO ingest pipeline found with version [${template._meta.version}]`); - } else { - this.logger.info(`Installing SLO ingest pipeline [${template.id}]`); - return this.execute(() => this.esClient.ingest.putPipeline(template)); - } - } - private async createIndex(indexName: string) { try { await this.execute(() => this.esClient.indices.create({ index: indexName })); @@ -194,26 +169,3 @@ async function fetchIndexTemplateVersion( return getTemplateRes?.index_templates?.[0]?.index_template?._meta?.version || null; } - -async function fetchIngestPipelineVersion( - id: string, - logger: Logger, - esClient: ElasticsearchClient -) { - const getPipelineRes = await retryTransientEsErrors< - Record - >( - () => - esClient.ingest.getPipeline( - { - id, - }, - { - ignore: [404], - } - ), - { logger } - ); - - return getPipelineRes?.[id]?._meta?.version || null; -} diff --git a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/apm_transaction_duration.test.ts.snap b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/apm_transaction_duration.test.ts.snap index dcb36e3ac06dd..e5eba04f5305c 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/apm_transaction_duration.test.ts.snap +++ b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/apm_transaction_duration.test.ts.snap @@ -190,16 +190,6 @@ Object { "field": "service.environment", }, }, - "slo.id": Object { - "terms": Object { - "field": "slo.id", - }, - }, - "slo.revision": Object { - "terms": Object { - "field": "slo.revision", - }, - }, } `; @@ -254,16 +244,6 @@ Object { "field": "service.name", }, }, - "slo.id": Object { - "terms": Object { - "field": "slo.id", - }, - }, - "slo.revision": Object { - "terms": Object { - "field": "slo.revision", - }, - }, } `; @@ -313,16 +293,6 @@ Object { "fixed_interval": "1m", }, }, - "slo.id": Object { - "terms": Object { - "field": "slo.id", - }, - }, - "slo.revision": Object { - "terms": Object { - "field": "slo.revision", - }, - }, "transaction.name": Object { "terms": Object { "field": "transaction.name", @@ -377,16 +347,6 @@ Object { "fixed_interval": "1m", }, }, - "slo.id": Object { - "terms": Object { - "field": "slo.id", - }, - }, - "slo.revision": Object { - "terms": Object { - "field": "slo.revision", - }, - }, "transaction.type": Object { "terms": Object { "field": "transaction.type", @@ -406,7 +366,7 @@ Object { "description": "Rolled-up SLI data for SLO: irrelevant [id: irrelevant, revision: 1]", "dest": Object { "index": ".slo-observability.sli-v3.3", - "pipeline": ".slo-observability.sli.pipeline-v3.3", + "pipeline": ".slo-observability.sli.pipeline-irrelevant-1", }, "frequency": "1m", "pivot": Object { @@ -463,16 +423,6 @@ Object { "field": "service.name", }, }, - "slo.id": Object { - "terms": Object { - "field": "slo.id", - }, - }, - "slo.revision": Object { - "terms": Object { - "field": "slo.revision", - }, - }, "transaction.name": Object { "terms": Object { "field": "transaction.name", @@ -541,20 +491,7 @@ Object { ], }, }, - "runtime_mappings": Object { - "slo.id": Object { - "script": Object { - "source": "emit('irrelevant')", - }, - "type": "keyword", - }, - "slo.revision": Object { - "script": Object { - "source": "emit(1)", - }, - "type": "long", - }, - }, + "runtime_mappings": Object {}, }, "sync": Object { "time": Object { @@ -577,7 +514,7 @@ Object { "description": "Rolled-up SLI data for SLO: irrelevant [id: irrelevant, revision: 1]", "dest": Object { "index": ".slo-observability.sli-v3.3", - "pipeline": ".slo-observability.sli.pipeline-v3.3", + "pipeline": ".slo-observability.sli.pipeline-irrelevant-1", }, "frequency": "1m", "pivot": Object { @@ -634,16 +571,6 @@ Object { "field": "service.name", }, }, - "slo.id": Object { - "terms": Object { - "field": "slo.id", - }, - }, - "slo.revision": Object { - "terms": Object { - "field": "slo.revision", - }, - }, "transaction.name": Object { "terms": Object { "field": "transaction.name", @@ -712,20 +639,7 @@ Object { ], }, }, - "runtime_mappings": Object { - "slo.id": Object { - "script": Object { - "source": "emit('irrelevant')", - }, - "type": "keyword", - }, - "slo.revision": Object { - "script": Object { - "source": "emit(1)", - }, - "type": "long", - }, - }, + "runtime_mappings": Object {}, }, "sync": Object { "time": Object { @@ -748,7 +662,7 @@ Object { "description": "Rolled-up SLI data for SLO: irrelevant [id: irrelevant, revision: 1]", "dest": Object { "index": ".slo-observability.sli-v3.3", - "pipeline": ".slo-observability.sli.pipeline-v3.3", + "pipeline": ".slo-observability.sli.pipeline-irrelevant-1", }, "frequency": "1m", "pivot": Object { @@ -796,16 +710,6 @@ Object { "field": "service.name", }, }, - "slo.id": Object { - "terms": Object { - "field": "slo.id", - }, - }, - "slo.revision": Object { - "terms": Object { - "field": "slo.revision", - }, - }, "transaction.name": Object { "terms": Object { "field": "transaction.name", @@ -874,20 +778,7 @@ Object { ], }, }, - "runtime_mappings": Object { - "slo.id": Object { - "script": Object { - "source": "emit('irrelevant')", - }, - "type": "keyword", - }, - "slo.revision": Object { - "script": Object { - "source": "emit(1)", - }, - "type": "long", - }, - }, + "runtime_mappings": Object {}, }, "sync": Object { "time": Object { diff --git a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/apm_transaction_error_rate.test.ts.snap b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/apm_transaction_error_rate.test.ts.snap index 53af7ad5777ce..92c5b8c09385c 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/apm_transaction_error_rate.test.ts.snap +++ b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/apm_transaction_error_rate.test.ts.snap @@ -178,16 +178,6 @@ Object { "field": "service.environment", }, }, - "slo.id": Object { - "terms": Object { - "field": "slo.id", - }, - }, - "slo.revision": Object { - "terms": Object { - "field": "slo.revision", - }, - }, } `; @@ -238,16 +228,6 @@ Object { "field": "service.name", }, }, - "slo.id": Object { - "terms": Object { - "field": "slo.id", - }, - }, - "slo.revision": Object { - "terms": Object { - "field": "slo.revision", - }, - }, } `; @@ -293,16 +273,6 @@ Object { "fixed_interval": "1m", }, }, - "slo.id": Object { - "terms": Object { - "field": "slo.id", - }, - }, - "slo.revision": Object { - "terms": Object { - "field": "slo.revision", - }, - }, "transaction.name": Object { "terms": Object { "field": "transaction.name", @@ -353,16 +323,6 @@ Object { "fixed_interval": "1m", }, }, - "slo.id": Object { - "terms": Object { - "field": "slo.id", - }, - }, - "slo.revision": Object { - "terms": Object { - "field": "slo.revision", - }, - }, "transaction.type": Object { "terms": Object { "field": "transaction.type", @@ -382,7 +342,7 @@ Object { "description": "Rolled-up SLI data for SLO: irrelevant [id: irrelevant, revision: 1]", "dest": Object { "index": ".slo-observability.sli-v3.3", - "pipeline": ".slo-observability.sli.pipeline-v3.3", + "pipeline": ".slo-observability.sli.pipeline-irrelevant-1", }, "frequency": "1m", "pivot": Object { @@ -430,16 +390,6 @@ Object { "field": "service.name", }, }, - "slo.id": Object { - "terms": Object { - "field": "slo.id", - }, - }, - "slo.revision": Object { - "terms": Object { - "field": "slo.revision", - }, - }, "transaction.name": Object { "terms": Object { "field": "transaction.name", @@ -504,20 +454,7 @@ Object { ], }, }, - "runtime_mappings": Object { - "slo.id": Object { - "script": Object { - "source": "emit('irrelevant')", - }, - "type": "keyword", - }, - "slo.revision": Object { - "script": Object { - "source": "emit(1)", - }, - "type": "long", - }, - }, + "runtime_mappings": Object {}, }, "sync": Object { "time": Object { @@ -540,7 +477,7 @@ Object { "description": "Rolled-up SLI data for SLO: irrelevant [id: irrelevant, revision: 1]", "dest": Object { "index": ".slo-observability.sli-v3.3", - "pipeline": ".slo-observability.sli.pipeline-v3.3", + "pipeline": ".slo-observability.sli.pipeline-irrelevant-1", }, "frequency": "1m", "pivot": Object { @@ -588,16 +525,6 @@ Object { "field": "service.name", }, }, - "slo.id": Object { - "terms": Object { - "field": "slo.id", - }, - }, - "slo.revision": Object { - "terms": Object { - "field": "slo.revision", - }, - }, "transaction.name": Object { "terms": Object { "field": "transaction.name", @@ -662,20 +589,7 @@ Object { ], }, }, - "runtime_mappings": Object { - "slo.id": Object { - "script": Object { - "source": "emit('irrelevant')", - }, - "type": "keyword", - }, - "slo.revision": Object { - "script": Object { - "source": "emit(1)", - }, - "type": "long", - }, - }, + "runtime_mappings": Object {}, }, "sync": Object { "time": Object { @@ -698,7 +612,7 @@ Object { "description": "Rolled-up SLI data for SLO: irrelevant [id: irrelevant, revision: 1]", "dest": Object { "index": ".slo-observability.sli-v3.3", - "pipeline": ".slo-observability.sli.pipeline-v3.3", + "pipeline": ".slo-observability.sli.pipeline-irrelevant-1", }, "frequency": "1m", "pivot": Object { @@ -737,16 +651,6 @@ Object { "field": "service.name", }, }, - "slo.id": Object { - "terms": Object { - "field": "slo.id", - }, - }, - "slo.revision": Object { - "terms": Object { - "field": "slo.revision", - }, - }, "transaction.name": Object { "terms": Object { "field": "transaction.name", @@ -811,20 +715,7 @@ Object { ], }, }, - "runtime_mappings": Object { - "slo.id": Object { - "script": Object { - "source": "emit('irrelevant')", - }, - "type": "keyword", - }, - "slo.revision": Object { - "script": Object { - "source": "emit(1)", - }, - "type": "long", - }, - }, + "runtime_mappings": Object {}, }, "sync": Object { "time": Object { diff --git a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/histogram.test.ts.snap b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/histogram.test.ts.snap index c0dae33244b3d..260a9406e7674 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/histogram.test.ts.snap +++ b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/histogram.test.ts.snap @@ -83,7 +83,7 @@ Object { "description": "Rolled-up SLI data for SLO: irrelevant [id: irrelevant, revision: 1]", "dest": Object { "index": ".slo-observability.sli-v3.3", - "pipeline": ".slo-observability.sli.pipeline-v3.3", + "pipeline": ".slo-observability.sli.pipeline-irrelevant-1", }, "frequency": "1m", "pivot": Object { @@ -153,16 +153,6 @@ Object { "fixed_interval": "2m", }, }, - "slo.id": Object { - "terms": Object { - "field": "slo.id", - }, - }, - "slo.revision": Object { - "terms": Object { - "field": "slo.revision", - }, - }, }, }, "settings": Object { @@ -199,20 +189,7 @@ Object { ], }, }, - "runtime_mappings": Object { - "slo.id": Object { - "script": Object { - "source": "emit('irrelevant')", - }, - "type": "keyword", - }, - "slo.revision": Object { - "script": Object { - "source": "emit(1)", - }, - "type": "long", - }, - }, + "runtime_mappings": Object {}, }, "sync": Object { "time": Object { @@ -235,7 +212,7 @@ Object { "description": "Rolled-up SLI data for SLO: irrelevant [id: irrelevant, revision: 1]", "dest": Object { "index": ".slo-observability.sli-v3.3", - "pipeline": ".slo-observability.sli.pipeline-v3.3", + "pipeline": ".slo-observability.sli.pipeline-irrelevant-1", }, "frequency": "1m", "pivot": Object { @@ -305,16 +282,6 @@ Object { "fixed_interval": "2m", }, }, - "slo.id": Object { - "terms": Object { - "field": "slo.id", - }, - }, - "slo.revision": Object { - "terms": Object { - "field": "slo.revision", - }, - }, }, }, "settings": Object { @@ -351,20 +318,7 @@ Object { ], }, }, - "runtime_mappings": Object { - "slo.id": Object { - "script": Object { - "source": "emit('irrelevant')", - }, - "type": "keyword", - }, - "slo.revision": Object { - "script": Object { - "source": "emit(1)", - }, - "type": "long", - }, - }, + "runtime_mappings": Object {}, }, "sync": Object { "time": Object { @@ -387,7 +341,7 @@ Object { "description": "Rolled-up SLI data for SLO: irrelevant [id: irrelevant, revision: 1]", "dest": Object { "index": ".slo-observability.sli-v3.3", - "pipeline": ".slo-observability.sli.pipeline-v3.3", + "pipeline": ".slo-observability.sli.pipeline-irrelevant-1", }, "frequency": "1m", "pivot": Object { @@ -448,16 +402,6 @@ Object { "fixed_interval": "1m", }, }, - "slo.id": Object { - "terms": Object { - "field": "slo.id", - }, - }, - "slo.revision": Object { - "terms": Object { - "field": "slo.revision", - }, - }, }, }, "settings": Object { @@ -494,20 +438,7 @@ Object { ], }, }, - "runtime_mappings": Object { - "slo.id": Object { - "script": Object { - "source": "emit('irrelevant')", - }, - "type": "keyword", - }, - "slo.revision": Object { - "script": Object { - "source": "emit(1)", - }, - "type": "long", - }, - }, + "runtime_mappings": Object {}, }, "sync": Object { "time": Object { diff --git a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/kql_custom.test.ts.snap b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/kql_custom.test.ts.snap index 4f5b239e982cf..26fb5dde0f784 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/kql_custom.test.ts.snap +++ b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/kql_custom.test.ts.snap @@ -124,7 +124,7 @@ Object { "description": "Rolled-up SLI data for SLO: irrelevant [id: irrelevant, revision: 1]", "dest": Object { "index": ".slo-observability.sli-v3.3", - "pipeline": ".slo-observability.sli.pipeline-v3.3", + "pipeline": ".slo-observability.sli.pipeline-irrelevant-1", }, "frequency": "1m", "pivot": Object { @@ -167,16 +167,6 @@ Object { "fixed_interval": "2m", }, }, - "slo.id": Object { - "terms": Object { - "field": "slo.id", - }, - }, - "slo.revision": Object { - "terms": Object { - "field": "slo.revision", - }, - }, }, }, "settings": Object { @@ -213,20 +203,7 @@ Object { ], }, }, - "runtime_mappings": Object { - "slo.id": Object { - "script": Object { - "source": "emit('irrelevant')", - }, - "type": "keyword", - }, - "slo.revision": Object { - "script": Object { - "source": "emit(1)", - }, - "type": "long", - }, - }, + "runtime_mappings": Object {}, }, "sync": Object { "time": Object { @@ -249,7 +226,7 @@ Object { "description": "Rolled-up SLI data for SLO: irrelevant [id: irrelevant, revision: 1]", "dest": Object { "index": ".slo-observability.sli-v3.3", - "pipeline": ".slo-observability.sli.pipeline-v3.3", + "pipeline": ".slo-observability.sli.pipeline-irrelevant-1", }, "frequency": "1m", "pivot": Object { @@ -292,16 +269,6 @@ Object { "fixed_interval": "2m", }, }, - "slo.id": Object { - "terms": Object { - "field": "slo.id", - }, - }, - "slo.revision": Object { - "terms": Object { - "field": "slo.revision", - }, - }, }, }, "settings": Object { @@ -338,20 +305,7 @@ Object { ], }, }, - "runtime_mappings": Object { - "slo.id": Object { - "script": Object { - "source": "emit('irrelevant')", - }, - "type": "keyword", - }, - "slo.revision": Object { - "script": Object { - "source": "emit(1)", - }, - "type": "long", - }, - }, + "runtime_mappings": Object {}, }, "sync": Object { "time": Object { @@ -374,7 +328,7 @@ Object { "description": "Rolled-up SLI data for SLO: irrelevant [id: irrelevant, revision: 1]", "dest": Object { "index": ".slo-observability.sli-v3.3", - "pipeline": ".slo-observability.sli.pipeline-v3.3", + "pipeline": ".slo-observability.sli.pipeline-irrelevant-1", }, "frequency": "1m", "pivot": Object { @@ -408,16 +362,6 @@ Object { "fixed_interval": "1m", }, }, - "slo.id": Object { - "terms": Object { - "field": "slo.id", - }, - }, - "slo.revision": Object { - "terms": Object { - "field": "slo.revision", - }, - }, }, }, "settings": Object { @@ -454,20 +398,7 @@ Object { ], }, }, - "runtime_mappings": Object { - "slo.id": Object { - "script": Object { - "source": "emit('irrelevant')", - }, - "type": "keyword", - }, - "slo.revision": Object { - "script": Object { - "source": "emit(1)", - }, - "type": "long", - }, - }, + "runtime_mappings": Object {}, }, "sync": Object { "time": Object { diff --git a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/metric_custom.test.ts.snap b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/metric_custom.test.ts.snap index 351c4d57b8c5c..c1317435fb97b 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/metric_custom.test.ts.snap +++ b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/metric_custom.test.ts.snap @@ -123,7 +123,7 @@ Object { "description": "Rolled-up SLI data for SLO: irrelevant [id: irrelevant, revision: 1]", "dest": Object { "index": ".slo-observability.sli-v3.3", - "pipeline": ".slo-observability.sli.pipeline-v3.3", + "pipeline": ".slo-observability.sli.pipeline-irrelevant-1", }, "frequency": "1m", "pivot": Object { @@ -204,16 +204,6 @@ Object { "fixed_interval": "2m", }, }, - "slo.id": Object { - "terms": Object { - "field": "slo.id", - }, - }, - "slo.revision": Object { - "terms": Object { - "field": "slo.revision", - }, - }, }, }, "settings": Object { @@ -250,20 +240,7 @@ Object { ], }, }, - "runtime_mappings": Object { - "slo.id": Object { - "script": Object { - "source": "emit('irrelevant')", - }, - "type": "keyword", - }, - "slo.revision": Object { - "script": Object { - "source": "emit(1)", - }, - "type": "long", - }, - }, + "runtime_mappings": Object {}, }, "sync": Object { "time": Object { @@ -286,7 +263,7 @@ Object { "description": "Rolled-up SLI data for SLO: irrelevant [id: irrelevant, revision: 1]", "dest": Object { "index": ".slo-observability.sli-v3.3", - "pipeline": ".slo-observability.sli.pipeline-v3.3", + "pipeline": ".slo-observability.sli.pipeline-irrelevant-1", }, "frequency": "1m", "pivot": Object { @@ -358,16 +335,6 @@ Object { "fixed_interval": "1m", }, }, - "slo.id": Object { - "terms": Object { - "field": "slo.id", - }, - }, - "slo.revision": Object { - "terms": Object { - "field": "slo.revision", - }, - }, }, }, "settings": Object { @@ -404,20 +371,7 @@ Object { ], }, }, - "runtime_mappings": Object { - "slo.id": Object { - "script": Object { - "source": "emit('irrelevant')", - }, - "type": "keyword", - }, - "slo.revision": Object { - "script": Object { - "source": "emit(1)", - }, - "type": "long", - }, - }, + "runtime_mappings": Object {}, }, "sync": Object { "time": Object { diff --git a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/timeslice_metric.test.ts.snap b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/timeslice_metric.test.ts.snap index 6ee25d4927910..449d1c2fb74d2 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/timeslice_metric.test.ts.snap +++ b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/timeslice_metric.test.ts.snap @@ -39,7 +39,7 @@ Object { "description": "Rolled-up SLI data for SLO: irrelevant [id: irrelevant, revision: 1]", "dest": Object { "index": ".slo-observability.sli-v3.3", - "pipeline": ".slo-observability.sli.pipeline-v3.3", + "pipeline": ".slo-observability.sli.pipeline-irrelevant-1", }, "frequency": "1m", "pivot": Object { @@ -174,16 +174,6 @@ Object { "fixed_interval": "2m", }, }, - "slo.id": Object { - "terms": Object { - "field": "slo.id", - }, - }, - "slo.revision": Object { - "terms": Object { - "field": "slo.revision", - }, - }, }, }, "settings": Object { @@ -217,20 +207,7 @@ Object { ], }, }, - "runtime_mappings": Object { - "slo.id": Object { - "script": Object { - "source": "emit('irrelevant')", - }, - "type": "keyword", - }, - "slo.revision": Object { - "script": Object { - "source": "emit(1)", - }, - "type": "long", - }, - }, + "runtime_mappings": Object {}, }, "sync": Object { "time": Object { @@ -253,7 +230,7 @@ Object { "description": "Rolled-up SLI data for SLO: irrelevant [id: irrelevant, revision: 1]", "dest": Object { "index": ".slo-observability.sli-v3.3", - "pipeline": ".slo-observability.sli.pipeline-v3.3", + "pipeline": ".slo-observability.sli.pipeline-irrelevant-1", }, "frequency": "1m", "pivot": Object { @@ -388,16 +365,6 @@ Object { "fixed_interval": "2m", }, }, - "slo.id": Object { - "terms": Object { - "field": "slo.id", - }, - }, - "slo.revision": Object { - "terms": Object { - "field": "slo.revision", - }, - }, }, }, "settings": Object { @@ -431,20 +398,7 @@ Object { ], }, }, - "runtime_mappings": Object { - "slo.id": Object { - "script": Object { - "source": "emit('irrelevant')", - }, - "type": "keyword", - }, - "slo.revision": Object { - "script": Object { - "source": "emit(1)", - }, - "type": "long", - }, - }, + "runtime_mappings": Object {}, }, "sync": Object { "time": Object { diff --git a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/apm_transaction_duration.ts b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/apm_transaction_duration.ts index afb37b4f0a105..85496cb91f6e4 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/apm_transaction_duration.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/apm_transaction_duration.ts @@ -16,9 +16,9 @@ import { import { DataViewsService } from '@kbn/data-views-plugin/common'; import { getElasticsearchQueryOrThrow, TransformGenerator } from '.'; import { + getSLOPipelineId, getSLOTransformId, SLO_DESTINATION_INDEX_NAME, - SLO_INGEST_PIPELINE_NAME, } from '../../../common/constants'; import { getSLOTransformTemplate } from '../../assets/transform_templates/slo_transform_template'; import { APMTransactionDurationIndicator, SLODefinition } from '../../domain/models'; @@ -40,7 +40,7 @@ export class ApmTransactionDurationTransformGenerator extends TransformGenerator this.buildTransformId(slo), this.buildDescription(slo), await this.buildSource(slo, slo.indicator, dataViewService), - this.buildDestination(), + this.buildDestination(slo), this.buildGroupBy(slo, slo.indicator), this.buildAggregations(slo, slo.indicator), this.buildSettings(slo), @@ -138,9 +138,9 @@ export class ApmTransactionDurationTransformGenerator extends TransformGenerator }; } - private buildDestination() { + private buildDestination(slo: SLODefinition) { return { - pipeline: SLO_INGEST_PIPELINE_NAME, + pipeline: getSLOPipelineId(slo.id, slo.revision), index: SLO_DESTINATION_INDEX_NAME, }; } diff --git a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/apm_transaction_error_rate.ts b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/apm_transaction_error_rate.ts index 863a31cfc508c..91b4af3a07aff 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/apm_transaction_error_rate.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/apm_transaction_error_rate.ts @@ -5,24 +5,24 @@ * 2.0. */ +import { estypes } from '@elastic/elasticsearch'; import { TransformPutTransformRequest } from '@elastic/elasticsearch/lib/api/types'; +import { DataViewsService } from '@kbn/data-views-plugin/common'; import { ALL_VALUE, apmTransactionErrorRateIndicatorSchema, timeslicesBudgetingMethodSchema, } from '@kbn/slo-schema'; -import { estypes } from '@elastic/elasticsearch'; -import { DataViewsService } from '@kbn/data-views-plugin/common'; import { getElasticsearchQueryOrThrow, TransformGenerator } from '.'; import { + getSLOPipelineId, getSLOTransformId, SLO_DESTINATION_INDEX_NAME, - SLO_INGEST_PIPELINE_NAME, } from '../../../common/constants'; import { getSLOTransformTemplate } from '../../assets/transform_templates/slo_transform_template'; import { APMTransactionErrorRateIndicator, SLODefinition } from '../../domain/models'; import { InvalidTransformError } from '../../errors'; -import { parseIndex, getTimesliceTargetComparator, getFilterRange } from './common'; +import { getFilterRange, getTimesliceTargetComparator, parseIndex } from './common'; export class ApmTransactionErrorRateTransformGenerator extends TransformGenerator { public async getTransformParams( @@ -38,7 +38,7 @@ export class ApmTransactionErrorRateTransformGenerator extends TransformGenerato this.buildTransformId(slo), this.buildDescription(slo), await this.buildSource(slo, slo.indicator, dataViewService), - this.buildDestination(), + this.buildDestination(slo), this.buildGroupBy(slo, slo.indicator), this.buildAggregations(slo), this.buildSettings(slo), @@ -136,9 +136,9 @@ export class ApmTransactionErrorRateTransformGenerator extends TransformGenerato }; } - private buildDestination() { + private buildDestination(slo: SLODefinition) { return { - pipeline: SLO_INGEST_PIPELINE_NAME, + pipeline: getSLOPipelineId(slo.id, slo.revision), index: SLO_DESTINATION_INDEX_NAME, }; } diff --git a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/histogram.ts b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/histogram.ts index 76325445a862c..c7c97639b92a8 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/histogram.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/histogram.ts @@ -13,17 +13,17 @@ import { } from '@kbn/slo-schema'; import { DataViewsService } from '@kbn/data-views-plugin/common'; -import { InvalidTransformError } from '../../errors'; -import { getSLOTransformTemplate } from '../../assets/transform_templates/slo_transform_template'; import { getElasticsearchQueryOrThrow, parseIndex, TransformGenerator } from '.'; import { + getSLOPipelineId, getSLOTransformId, SLO_DESTINATION_INDEX_NAME, - SLO_INGEST_PIPELINE_NAME, } from '../../../common/constants'; +import { getSLOTransformTemplate } from '../../assets/transform_templates/slo_transform_template'; import { SLODefinition } from '../../domain/models'; +import { InvalidTransformError } from '../../errors'; import { GetHistogramIndicatorAggregation } from '../aggregations'; -import { getTimesliceTargetComparator, getFilterRange } from './common'; +import { getFilterRange, getTimesliceTargetComparator } from './common'; export class HistogramTransformGenerator extends TransformGenerator { public async getTransformParams( @@ -39,7 +39,7 @@ export class HistogramTransformGenerator extends TransformGenerator { this.buildTransformId(slo), this.buildDescription(slo), await this.buildSource(slo, slo.indicator, dataViewService), - this.buildDestination(), + this.buildDestination(slo), this.buildCommonGroupBy(slo, slo.indicator.params.timestampField), this.buildAggregations(slo, slo.indicator), this.buildSettings(slo, slo.indicator.params.timestampField), @@ -75,9 +75,9 @@ export class HistogramTransformGenerator extends TransformGenerator { }; } - private buildDestination() { + private buildDestination(slo: SLODefinition) { return { - pipeline: SLO_INGEST_PIPELINE_NAME, + pipeline: getSLOPipelineId(slo.id, slo.revision), index: SLO_DESTINATION_INDEX_NAME, }; } diff --git a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/kql_custom.ts b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/kql_custom.ts index d721140f243cf..1924bc1a4c344 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/kql_custom.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/kql_custom.ts @@ -9,16 +9,16 @@ import { TransformPutTransformRequest } from '@elastic/elasticsearch/lib/api/typ import { kqlCustomIndicatorSchema, timeslicesBudgetingMethodSchema } from '@kbn/slo-schema'; import { DataViewsService } from '@kbn/data-views-plugin/common'; -import { InvalidTransformError } from '../../errors'; -import { getSLOTransformTemplate } from '../../assets/transform_templates/slo_transform_template'; import { getElasticsearchQueryOrThrow, parseIndex, TransformGenerator } from '.'; import { + getSLOPipelineId, getSLOTransformId, SLO_DESTINATION_INDEX_NAME, - SLO_INGEST_PIPELINE_NAME, } from '../../../common/constants'; +import { getSLOTransformTemplate } from '../../assets/transform_templates/slo_transform_template'; import { KQLCustomIndicator, SLODefinition } from '../../domain/models'; -import { getTimesliceTargetComparator, getFilterRange } from './common'; +import { InvalidTransformError } from '../../errors'; +import { getFilterRange, getTimesliceTargetComparator } from './common'; export class KQLCustomTransformGenerator extends TransformGenerator { public async getTransformParams( @@ -34,7 +34,7 @@ export class KQLCustomTransformGenerator extends TransformGenerator { this.buildTransformId(slo), this.buildDescription(slo), await this.buildSource(slo, slo.indicator, dataViewService), - this.buildDestination(), + this.buildDestination(slo), this.buildCommonGroupBy(slo, slo.indicator.params.timestampField), this.buildAggregations(slo, slo.indicator), this.buildSettings(slo, slo.indicator.params.timestampField), @@ -69,9 +69,9 @@ export class KQLCustomTransformGenerator extends TransformGenerator { }; } - private buildDestination() { + private buildDestination(slo: SLODefinition) { return { - pipeline: SLO_INGEST_PIPELINE_NAME, + pipeline: getSLOPipelineId(slo.id, slo.revision), index: SLO_DESTINATION_INDEX_NAME, }; } diff --git a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/metric_custom.ts b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/metric_custom.ts index c6127b600a4eb..5717b05a466de 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/metric_custom.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/metric_custom.ts @@ -9,17 +9,17 @@ import { TransformPutTransformRequest } from '@elastic/elasticsearch/lib/api/typ import { metricCustomIndicatorSchema, timeslicesBudgetingMethodSchema } from '@kbn/slo-schema'; import { DataViewsService } from '@kbn/data-views-plugin/common'; -import { InvalidTransformError } from '../../errors'; -import { getSLOTransformTemplate } from '../../assets/transform_templates/slo_transform_template'; import { getElasticsearchQueryOrThrow, parseIndex, TransformGenerator } from '.'; import { + getSLOPipelineId, getSLOTransformId, SLO_DESTINATION_INDEX_NAME, - SLO_INGEST_PIPELINE_NAME, } from '../../../common/constants'; +import { getSLOTransformTemplate } from '../../assets/transform_templates/slo_transform_template'; import { MetricCustomIndicator, SLODefinition } from '../../domain/models'; +import { InvalidTransformError } from '../../errors'; import { GetCustomMetricIndicatorAggregation } from '../aggregations'; -import { getTimesliceTargetComparator, getFilterRange } from './common'; +import { getFilterRange, getTimesliceTargetComparator } from './common'; export const INVALID_EQUATION_REGEX = /[^A-Z|+|\-|\s|\d+|\.|\(|\)|\/|\*|>|<|=|\?|\:|&|\!|\|]+/g; @@ -37,7 +37,7 @@ export class MetricCustomTransformGenerator extends TransformGenerator { this.buildTransformId(slo), this.buildDescription(slo), await this.buildSource(slo, slo.indicator, dataViewService), - this.buildDestination(), + this.buildDestination(slo), this.buildCommonGroupBy(slo, slo.indicator.params.timestampField), this.buildAggregations(slo, slo.indicator), this.buildSettings(slo, slo.indicator.params.timestampField), @@ -72,9 +72,9 @@ export class MetricCustomTransformGenerator extends TransformGenerator { }; } - private buildDestination() { + private buildDestination(slo: SLODefinition) { return { - pipeline: SLO_INGEST_PIPELINE_NAME, + pipeline: getSLOPipelineId(slo.id, slo.revision), index: SLO_DESTINATION_INDEX_NAME, }; } diff --git a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/synthetics_availability.test.ts b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/synthetics_availability.test.ts index f59c1fd9a96e6..f9caeb9f57c31 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/synthetics_availability.test.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/synthetics_availability.test.ts @@ -32,7 +32,7 @@ describe('Synthetics Availability Transform Generator', () => { description: 'Rolled-up SLI data for SLO: irrelevant [id: irrelevant, revision: 1]', dest: { index: '.slo-observability.sli-v3.3', - pipeline: '.slo-observability.sli.pipeline-v3.3', + pipeline: '.slo-observability.sli.pipeline-irrelevant-1', }, frequency: '1m', pivot: { @@ -94,16 +94,6 @@ describe('Synthetics Availability Transform Generator', () => { field: 'monitor.id', }, }, - 'slo.id': { - terms: { - field: 'slo.id', - }, - }, - 'slo.revision': { - terms: { - field: 'slo.revision', - }, - }, }, }, settings: { @@ -135,20 +125,7 @@ describe('Synthetics Availability Transform Generator', () => { ], }, }, - runtime_mappings: { - 'slo.id': { - script: { - source: "emit('irrelevant')", - }, - type: 'keyword', - }, - 'slo.revision': { - script: { - source: 'emit(1)', - }, - type: 'long', - }, - }, + runtime_mappings: {}, }, sync: { time: { diff --git a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/synthetics_availability.ts b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/synthetics_availability.ts index 5839a5611351e..e15c1d09a2044 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/synthetics_availability.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/synthetics_availability.ts @@ -5,26 +5,26 @@ * 2.0. */ -import { TransformPutTransformRequest } from '@elastic/elasticsearch/lib/api/types'; import { estypes } from '@elastic/elasticsearch'; +import { TransformPutTransformRequest } from '@elastic/elasticsearch/lib/api/types'; +import { DataViewsService } from '@kbn/data-views-plugin/common'; import { ALL_VALUE, - syntheticsAvailabilityIndicatorSchema, occurrencesBudgetingMethodSchema, SyntheticsAvailabilityIndicator, + syntheticsAvailabilityIndicatorSchema, } from '@kbn/slo-schema'; -import { DataViewsService } from '@kbn/data-views-plugin/common'; import { getElasticsearchQueryOrThrow, TransformGenerator } from '.'; import { + getSLOPipelineId, getSLOTransformId, SLO_DESTINATION_INDEX_NAME, - SLO_INGEST_PIPELINE_NAME, - SYNTHETICS_INDEX_PATTERN, SYNTHETICS_DEFAULT_GROUPINGS, + SYNTHETICS_INDEX_PATTERN, } from '../../../common/constants'; import { getSLOTransformTemplate } from '../../assets/transform_templates/slo_transform_template'; -import { InvalidTransformError } from '../../errors'; import { SLODefinition } from '../../domain/models'; +import { InvalidTransformError } from '../../errors'; import { getFilterRange } from './common'; export class SyntheticsAvailabilityTransformGenerator extends TransformGenerator { @@ -41,7 +41,7 @@ export class SyntheticsAvailabilityTransformGenerator extends TransformGenerator this.buildTransformId(slo), this.buildDescription(slo), await this.buildSource(slo, slo.indicator, spaceId, dataViewService), - this.buildDestination(), + this.buildDestination(slo), this.buildGroupBy(slo, slo.indicator), this.buildAggregations(slo), this.buildSettings(slo, 'event.ingested'), @@ -168,9 +168,9 @@ export class SyntheticsAvailabilityTransformGenerator extends TransformGenerator }; } - private buildDestination() { + private buildDestination(slo: SLODefinition) { return { - pipeline: SLO_INGEST_PIPELINE_NAME, + pipeline: getSLOPipelineId(slo.id, slo.revision), index: SLO_DESTINATION_INDEX_NAME, }; } diff --git a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/timeslice_metric.ts b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/timeslice_metric.ts index 579772b0eb1de..b0e32f7094a2f 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/timeslice_metric.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/timeslice_metric.ts @@ -6,22 +6,22 @@ */ import { TransformPutTransformRequest } from '@elastic/elasticsearch/lib/api/types'; +import { DataViewsService } from '@kbn/data-views-plugin/common'; import { timesliceMetricComparatorMapping, TimesliceMetricIndicator, timesliceMetricIndicatorSchema, timeslicesBudgetingMethodSchema, } from '@kbn/slo-schema'; -import { DataViewsService } from '@kbn/data-views-plugin/common'; -import { InvalidTransformError } from '../../errors'; -import { getSLOTransformTemplate } from '../../assets/transform_templates/slo_transform_template'; import { getElasticsearchQueryOrThrow, parseIndex, TransformGenerator } from '.'; import { - SLO_DESTINATION_INDEX_NAME, - SLO_INGEST_PIPELINE_NAME, + getSLOPipelineId, getSLOTransformId, + SLO_DESTINATION_INDEX_NAME, } from '../../../common/constants'; +import { getSLOTransformTemplate } from '../../assets/transform_templates/slo_transform_template'; import { SLODefinition } from '../../domain/models'; +import { InvalidTransformError } from '../../errors'; import { GetTimesliceMetricIndicatorAggregation } from '../aggregations'; import { getFilterRange } from './common'; @@ -41,7 +41,7 @@ export class TimesliceMetricTransformGenerator extends TransformGenerator { this.buildTransformId(slo), this.buildDescription(slo), await this.buildSource(slo, slo.indicator, dataViewService), - this.buildDestination(), + this.buildDestination(slo), this.buildCommonGroupBy(slo, slo.indicator.params.timestampField), this.buildAggregations(slo, slo.indicator), this.buildSettings(slo, slo.indicator.params.timestampField), @@ -76,9 +76,9 @@ export class TimesliceMetricTransformGenerator extends TransformGenerator { }; } - private buildDestination() { + private buildDestination(slo: SLODefinition) { return { - pipeline: SLO_INGEST_PIPELINE_NAME, + pipeline: getSLOPipelineId(slo.id, slo.revision), index: SLO_DESTINATION_INDEX_NAME, }; } diff --git a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/transform_generator.test.ts b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/transform_generator.test.ts index 32234cc17a73f..ffb165fdb4326 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/transform_generator.test.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/transform_generator.test.ts @@ -11,27 +11,14 @@ import { ApmTransactionErrorRateTransformGenerator } from './apm_transaction_err const generator = new ApmTransactionErrorRateTransformGenerator(); describe('Transform Generator', () => { - it('builds common runtime mappings without group by', async () => { + it('builds empty runtime mappings without group by', async () => { const slo = createSLO({ id: 'irrelevant', indicator: createAPMTransactionErrorRateIndicator(), }); - const transform = generator.buildCommonRuntimeMappings(slo); + const commonRuntime = generator.buildCommonRuntimeMappings(slo); - expect(transform).toEqual({ - 'slo.id': { - script: { - source: "emit('irrelevant')", - }, - type: 'keyword', - }, - 'slo.revision': { - script: { - source: 'emit(1)', - }, - type: 'long', - }, - }); + expect(commonRuntime).toEqual({}); const commonGroupBy = generator.buildCommonGroupBy(slo); @@ -42,16 +29,6 @@ describe('Transform Generator', () => { fixed_interval: '1m', }, }, - 'slo.id': { - terms: { - field: 'slo.id', - }, - }, - 'slo.revision': { - terms: { - field: 'slo.revision', - }, - }, }); }); @@ -66,20 +43,7 @@ describe('Transform Generator', () => { }); const commonRuntime = generator.buildCommonRuntimeMappings(slo); - expect(commonRuntime).toEqual({ - 'slo.id': { - script: { - source: "emit('irrelevant')", - }, - type: 'keyword', - }, - 'slo.revision': { - script: { - source: 'emit(1)', - }, - type: 'long', - }, - }); + expect(commonRuntime).toEqual({}); const commonGroupBy = generator.buildCommonGroupBy(slo); @@ -95,16 +59,6 @@ describe('Transform Generator', () => { field: 'example', }, }, - 'slo.id': { - terms: { - field: 'slo.id', - }, - }, - 'slo.revision': { - terms: { - field: 'slo.revision', - }, - }, }); } ); @@ -118,20 +72,7 @@ describe('Transform Generator', () => { }); const commonRuntime = generator.buildCommonRuntimeMappings(slo); - expect(commonRuntime).toEqual({ - 'slo.id': { - script: { - source: "emit('irrelevant')", - }, - type: 'keyword', - }, - 'slo.revision': { - script: { - source: 'emit(1)', - }, - type: 'long', - }, - }); + expect(commonRuntime).toEqual({}); const commonGroupBy = generator.buildCommonGroupBy(slo); @@ -152,16 +93,6 @@ describe('Transform Generator', () => { field: 'example2', }, }, - 'slo.id': { - terms: { - field: 'slo.id', - }, - }, - 'slo.revision': { - terms: { - field: 'slo.revision', - }, - }, }); }); }); diff --git a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/transform_generator.ts b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/transform_generator.ts index 37e20144435d7..8ae6eeb52c9be 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/transform_generator.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/transform_generator.ts @@ -23,18 +23,6 @@ export abstract class TransformGenerator { public buildCommonRuntimeMappings(slo: SLODefinition, dataView?: DataView): MappingRuntimeFields { return { - 'slo.id': { - type: 'keyword', - script: { - source: `emit('${slo.id}')`, - }, - }, - 'slo.revision': { - type: 'long', - script: { - source: `emit(${slo.revision})`, - }, - }, ...(dataView?.getRuntimeMappings?.() ?? {}), }; } @@ -70,8 +58,6 @@ export abstract class TransformGenerator { : {}; return { - 'slo.id': { terms: { field: 'slo.id' } }, - 'slo.revision': { terms: { field: 'slo.revision' } }, ...groupings, ...extraGroupByFields, // @timestamp field defined in the destination index diff --git a/x-pack/plugins/observability_solution/slo/server/services/transform_manager.ts b/x-pack/plugins/observability_solution/slo/server/services/transform_manager.ts index febd24a457222..822817962a2e9 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/transform_manager.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/transform_manager.ts @@ -134,7 +134,7 @@ export class DefaultTransformManager implements TransformManager { this.esClient.transform .scheduleNowTransform({ transform_id: transformId }) .then(() => { - this.logger.info(`SLO transform [${transformId}] scheduled now successfully`); + this.logger.debug(`SLO transform [${transformId}] scheduled now successfully`); }) .catch((e) => { this.logger.error(`Cannot schedule now SLO transform [${transformId}]`); diff --git a/x-pack/plugins/observability_solution/slo/server/services/update_slo.test.ts b/x-pack/plugins/observability_solution/slo/server/services/update_slo.test.ts index 0c68d20b2308c..7f8f8ff1e3150 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/update_slo.test.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/update_slo.test.ts @@ -313,10 +313,10 @@ describe('UpdateSLO', () => { ).rejects.toThrowError('Transform install error'); expect(mockRepository.save).toHaveBeenCalledWith(originalSlo); + expect(mockEsClient.ingest.deletePipeline).toHaveBeenCalledTimes(1); // for the sli only expect(mockSummaryTransformManager.stop).not.toHaveBeenCalled(); expect(mockSummaryTransformManager.uninstall).not.toHaveBeenCalled(); - expect(mockEsClient.ingest.deletePipeline).not.toHaveBeenCalled(); expect(mockTransformManager.stop).not.toHaveBeenCalled(); expect(mockTransformManager.uninstall).not.toHaveBeenCalled(); }); diff --git a/x-pack/plugins/observability_solution/slo/server/services/update_slo.ts b/x-pack/plugins/observability_solution/slo/server/services/update_slo.ts index c990024a6d03b..3175402eb1476 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/update_slo.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/update_slo.ts @@ -10,6 +10,7 @@ import { UpdateSLOParams, UpdateSLOResponse, updateSLOResponseSchema } from '@kb import { asyncForEach } from '@kbn/std'; import { isEqual, pick } from 'lodash'; import { + getSLOPipelineId, getSLOSummaryPipelineId, getSLOSummaryTransformId, getSLOTransformId, @@ -17,6 +18,7 @@ import { SLO_SUMMARY_DESTINATION_INDEX_PATTERN, SLO_SUMMARY_TEMP_INDEX_NAME, } from '../../common/constants'; +import { getSLOPipelineTemplate } from '../assets/ingest_templates/slo_pipeline_template'; import { getSLOSummaryPipelineTemplate } from '../assets/ingest_templates/slo_summary_pipeline_template'; import { SLODefinition } from '../domain/models'; import { validateSLO } from '../domain/services'; @@ -71,9 +73,20 @@ export class UpdateSLO { rollbackOperations.push(() => this.repository.save(originalSlo)); if (!requireRevisionBump) { - // At this point, we still need to update the summary pipeline to include the changes (name, desc, tags, ...) in the summary index + // At this point, we still need to update the sli and summary pipeline to include the changes (id and revision in the rollup index) and (name, desc, tags, ...) in the summary index try { + await retryTransientEsErrors( + () => this.esClient.ingest.putPipeline(getSLOPipelineTemplate(updatedSlo)), + { logger: this.logger } + ); + rollbackOperations.push(() => + this.esClient.ingest.deletePipeline( + { id: getSLOPipelineId(updatedSlo.id, updatedSlo.revision) }, + { ignore: [404] } + ) + ); + await retryTransientEsErrors( () => this.esClient.ingest.putPipeline( @@ -108,6 +121,17 @@ export class UpdateSLO { const updatedSummaryTransformId = getSLOSummaryTransformId(updatedSlo.id, updatedSlo.revision); try { + await retryTransientEsErrors( + () => this.esClient.ingest.putPipeline(getSLOPipelineTemplate(updatedSlo)), + { logger: this.logger } + ); + rollbackOperations.push(() => + this.esClient.ingest.deletePipeline( + { id: getSLOPipelineId(updatedSlo.id, updatedSlo.revision) }, + { ignore: [404] } + ) + ); + await this.transformManager.install(updatedSlo); rollbackOperations.push(() => this.transformManager.uninstall(updatedRollupTransformId)); @@ -188,6 +212,11 @@ export class UpdateSLO { { id: getSLOSummaryPipelineId(originalSlo.id, originalSlo.revision) }, { ignore: [404] } ); + + await this.esClient.ingest.deletePipeline( + { id: getSLOPipelineId(originalSlo.id, originalSlo.revision) }, + { ignore: [404] } + ); } catch (err) { // Any errors here should not prevent moving forward. // Worst case we keep rolling up data for the previous revision number. diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/common/monitor_test_result/single_ping_result.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/common/monitor_test_result/single_ping_result.tsx index cf6e0f00ff570..7d2027648450d 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/common/monitor_test_result/single_ping_result.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/common/monitor_test_result/single_ping_result.tsx @@ -11,42 +11,66 @@ import { EuiDescriptionListTitle, EuiDescriptionListDescription, EuiBadge, + EuiLink, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { Ping } from '../../../../../../common/runtime_types'; import { formatTestDuration } from '../../../utils/monitor_test_result/test_time_formats'; -export const SinglePingResult = ({ ping, loading }: { ping?: Ping; loading: boolean }) => { - const ip = !loading ? ping?.resolve?.ip : undefined; - const durationUs = !loading ? ping?.monitor?.duration?.us ?? NaN : NaN; - const rtt = !loading ? ping?.resolve?.rtt?.us ?? NaN : NaN; - const url = !loading ? ping?.url?.full : undefined; - const responseStatus = !loading ? ping?.http?.response?.status_code : undefined; +export const SinglePingResult = ({ ping }: { ping?: Ping }) => { + const ip = ping?.resolve?.ip; + const durationUs = ping?.monitor?.duration?.us ?? NaN; + const rtt = ping?.resolve?.rtt?.us ?? NaN; + const url = ping?.url?.full; + const responseStatus = ping?.http?.response?.status_code; return ( - - IP - {ip} - {DURATION_LABEL} - - {isNaN(durationUs) ? '' : formatTestDuration(durationUs)} - - rtt - - {isNaN(rtt) ? '' : formatTestDuration(rtt)} - - URL - {url} + <> + + + {i18n.translate('xpack.synthetics.singlePingResult.ipDescriptionListTitleLabel', { + defaultMessage: 'IP', + })} + + {ip} + {DURATION_LABEL} + + {isNaN(durationUs) ? '' : formatTestDuration(durationUs)} + + + {i18n.translate('xpack.synthetics.singlePingResult.rttDescriptionListTitleLabel', { + defaultMessage: 'rtt', + })} + + + {isNaN(rtt) ? '' : formatTestDuration(rtt)} + + + {i18n.translate('xpack.synthetics.singlePingResult.urlDescriptionListTitleLabel', { + defaultMessage: 'URL', + })} + + + + {url} + + - {responseStatus ? ( - <> - Response status - - {responseStatus} - - - ) : null} - + {responseStatus ? ( + <> + + {i18n.translate( + 'xpack.synthetics.singlePingResult.responseStatusDescriptionListTitleLabel', + { defaultMessage: 'Response status' } + )} + + + {responseStatus} + + + ) : null} + + ); }; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/last_test_run.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/last_test_run.tsx index 5f8d264585f6f..482e13c54689f 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/last_test_run.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/last_test_run.tsx @@ -19,6 +19,7 @@ import { EuiText, EuiTitle, useEuiTheme, + EuiProgress, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -87,6 +88,7 @@ export const LastTestRunComponent = ({ return ( + {loading && } {!(loading && !latestPing) && latestPing?.error ? ( ) : ( - + )} ); @@ -188,13 +190,13 @@ const PanelHeader = ({ return ( <> - {TitleNode} + {TitleNode} 0 ? 'fail' : 'success')} /> - + {lastRunTimestamp} diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/monitor_summary.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/monitor_summary.tsx index 6aa7cec78a955..2aba24a4b8cad 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/monitor_summary.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/monitor_summary.tsx @@ -118,7 +118,7 @@ export const MonitorSummary = () => { /> - + diff --git a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.test.ts b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.test.ts index 58227c38cfb54..b0ce8c17c6d0c 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.test.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.test.ts @@ -186,7 +186,7 @@ describe('updateState', () => { describe('setRecoveredAlertsContext', () => { const alertUuid = 'alert-id'; - const location = 'US Central'; + const location = 'us_west'; const configId = '12345'; const idWithLocation = `${configId}-${location}`; const basePath = { @@ -222,13 +222,15 @@ describe('setRecoveredAlertsContext', () => { getRecoveredAlerts: jest.fn().mockReturnValue([ { alert: { - getId: () => alertUuid, - getState: () => ({ - idWithLocation, - monitorName: 'test-monitor', - }), - setContext: jest.fn(), getUuid: () => alertUuid, + getId: () => idWithLocation, + getState: () => ({}), + setContext: jest.fn(), + }, + hit: { + 'kibana.alert.instance.id': idWithLocation, + 'location.id': location, + configId, }, }, ]), @@ -264,11 +266,10 @@ describe('setRecoveredAlertsContext', () => { tz: 'UTC', }); expect(alertsClientMock.setAlertData).toBeCalledWith({ - id: 'alert-id', + id: idWithLocation, context: { checkedAt: 'Feb 26, 2023 @ 00:00:00.000', configId: '12345', - idWithLocation, linkMessage: '', alertDetailsUrl: 'https://localhost:5601/app/observability/alerts/alert-id', monitorName: 'test-monitor', @@ -280,6 +281,8 @@ describe('setRecoveredAlertsContext', () => { 'Monitor "test-monitor" from Unnamed-location is recovered. Checked at February 25, 2023 7:00 PM.', stateId: '123456', status: 'recovered', + locationId: location, + idWithLocation, }, }); }); @@ -292,13 +295,15 @@ describe('setRecoveredAlertsContext', () => { getRecoveredAlerts: jest.fn().mockReturnValue([ { alert: { - getId: () => alertUuid, - getState: () => ({ - idWithLocation, - monitorName: 'test-monitor', - }), - setContext: jest.fn(), getUuid: () => alertUuid, + getId: () => idWithLocation, + getState: () => ({}), + setContext: jest.fn(), + }, + hit: { + 'kibana.alert.instance.id': idWithLocation, + 'location.id': location, + configId, }, }, ]), @@ -334,14 +339,13 @@ describe('setRecoveredAlertsContext', () => { tz: 'UTC', }); expect(alertsClientMock.setAlertData).toBeCalledWith({ - id: 'alert-id', + id: idWithLocation, context: { configId: '12345', checkedAt: 'Feb 26, 2023 @ 00:00:00.000', monitorUrl: '(unavailable)', reason: 'Monitor "test-monitor" from Unnamed-location is recovered. Checked at February 25, 2023 7:00 PM.', - idWithLocation, linkMessage: '', alertDetailsUrl: 'https://localhost:5601/app/observability/alerts/alert-id', monitorName: 'test-monitor', @@ -350,6 +354,8 @@ describe('setRecoveredAlertsContext', () => { stateId: '123456', status: 'recovered', monitorUrlLabel: 'URL', + idWithLocation, + locationId: location, }, }); }); @@ -362,15 +368,15 @@ describe('setRecoveredAlertsContext', () => { getRecoveredAlerts: jest.fn().mockReturnValue([ { alert: { - getId: () => alertUuid, - getState: () => ({ - idWithLocation, - monitorName: 'test-monitor', - locationId: 'us_west', - configId: '12345-67891', - }), - setContext: jest.fn(), + getId: () => idWithLocation, getUuid: () => alertUuid, + getState: () => ({}), + setContext: jest.fn(), + }, + hit: { + 'kibana.alert.instance.id': idWithLocation, + 'location.id': location, + configId, }, }, ]), @@ -382,7 +388,7 @@ describe('setRecoveredAlertsContext', () => { configId, monitorQueryId: 'stale-config', status: 'down', - locationId: 'location', + locationId: location, ping: { state: { id: '123456', @@ -406,9 +412,9 @@ describe('setRecoveredAlertsContext', () => { tz: 'UTC', }); expect(alertsClientMock.setAlertData).toBeCalledWith({ - id: 'alert-id', + id: idWithLocation, context: { - configId: '12345-67891', + configId, idWithLocation, alertDetailsUrl: 'https://localhost:5601/app/observability/alerts/alert-id', monitorName: 'test-monitor', @@ -416,10 +422,10 @@ describe('setRecoveredAlertsContext', () => { recoveryReason: 'the monitor is now up again. It ran successfully at Feb 26, 2023 @ 00:00:00.000', recoveryStatus: 'is now up', - locationId: 'us_west', + locationId: location, checkedAt: 'Feb 26, 2023 @ 00:00:00.000', linkMessage: - '- Link: https://localhost:5601/app/synthetics/monitor/12345-67891/errors/123456?locationId=us_west', + '- Link: https://localhost:5601/app/synthetics/monitor/12345/errors/123456?locationId=us_west', monitorUrl: '(unavailable)', monitorUrlLabel: 'URL', reason: diff --git a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.ts b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.ts index 165a11ea67856..25d2265ff3ff6 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.ts @@ -186,6 +186,9 @@ export const setRecoveredAlertsContext = ({ const alertUuid = recoveredAlert.alert.getUuid(); const state = recoveredAlert.alert.getState(); + const alertHit = recoveredAlert.hit; + const locationId = alertHit?.['location.id']; + const configId = alertHit?.configId; let recoveryReason = ''; let recoveryStatus = i18n.translate( @@ -199,15 +202,14 @@ export const setRecoveredAlertsContext = ({ let monitorSummary: MonitorSummaryStatusRule | null = null; let lastErrorMessage; - if (state?.idWithLocation && staleDownConfigs[state.idWithLocation]) { - const { idWithLocation, locationId } = state; - const downConfig = staleDownConfigs[idWithLocation]; - const { ping, configId } = downConfig; + if (recoveredAlertId && locationId && staleDownConfigs[recoveredAlertId]) { + const downConfig = staleDownConfigs[recoveredAlertId]; + const { ping } = downConfig; monitorSummary = getMonitorSummary( ping, RECOVERED_LABEL, locationId, - configId, + downConfig.configId, dateFormat, tz ); @@ -242,12 +244,11 @@ export const setRecoveredAlertsContext = ({ } } - if (state?.idWithLocation && upConfigs[state.idWithLocation]) { - const { idWithLocation, configId, locationId } = state; + if (configId && recoveredAlertId && locationId && upConfigs[recoveredAlertId]) { // pull the last error from state, since it is not available on the up ping - lastErrorMessage = state.lastErrorMessage; + lastErrorMessage = alertHit?.['error.message']; - const upConfig = upConfigs[idWithLocation]; + const upConfig = upConfigs[recoveredAlertId]; isUp = Boolean(upConfig) || false; const ping = upConfig.ping; @@ -290,6 +291,8 @@ export const setRecoveredAlertsContext = ({ const context = { ...state, ...(monitorSummary ? monitorSummary : {}), + locationId, + idWithLocation: recoveredAlertId, lastErrorMessage, recoveryStatus, linkMessage, diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/add_monitor.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/add_monitor.ts index 1fba8c9c81002..57f305b0ec2ef 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/add_monitor.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/add_monitor.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; import { SavedObjectsErrorHelpers } from '@kbn/core/server'; import { i18n } from '@kbn/i18n'; +import { validatePermissions } from './edit_monitor'; import { InvalidLocationError } from '../../synthetics_service/project_monitor/normalizers/common_fields'; import { AddEditMonitorAPI, CreateMonitorPayLoad } from './add_monitor/add_monitor_api'; import { SyntheticsRestApiRouteFactory } from '../types'; @@ -82,6 +83,14 @@ export const addSyntheticsMonitorRoute: SyntheticsRestApiRouteFactory = () => ({ const normalizedMonitor = validationResult.decodedMonitor; + const err = await validatePermissions(routeContext, normalizedMonitor.locations); + if (err) { + return response.forbidden({ + body: { + message: err, + }, + }); + } const nameError = await addMonitorAPI.validateUniqueMonitorName(normalizedMonitor.name); if (nameError) { return response.badRequest({ diff --git a/x-pack/plugins/observability_solution/synthetics/server/types.ts b/x-pack/plugins/observability_solution/synthetics/server/types.ts index b5a8735e4e715..6209055fc6778 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/types.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/types.ts @@ -30,7 +30,7 @@ import { EncryptedSavedObjectsPluginSetup, EncryptedSavedObjectsPluginStart, } from '@kbn/encrypted-saved-objects-plugin/server'; -import { PluginSetupContract } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { RuleRegistryPluginSetupContract } from '@kbn/rule-registry-plugin/server'; import { TaskManagerSetupContract, @@ -63,7 +63,7 @@ export interface SyntheticsServerSetup { } export interface SyntheticsPluginsSetupDependencies { - features: PluginSetupContract; + features: FeaturesPluginSetup; alerting: any; observability: ObservabilityPluginSetup; usageCollection: UsageCollectionSetup; diff --git a/x-pack/plugins/observability_solution/uptime/public/legacy_uptime/components/common/charts/__snapshots__/donut_chart.test.tsx.snap b/x-pack/plugins/observability_solution/uptime/public/legacy_uptime/components/common/charts/__snapshots__/donut_chart.test.tsx.snap index 639557a2b9e1a..226b31e3d1311 100644 --- a/x-pack/plugins/observability_solution/uptime/public/legacy_uptime/components/common/charts/__snapshots__/donut_chart.test.tsx.snap +++ b/x-pack/plugins/observability_solution/uptime/public/legacy_uptime/components/common/charts/__snapshots__/donut_chart.test.tsx.snap @@ -467,7 +467,7 @@ exports[`DonutChart component passes correct props without errors for valid prop "barBackground": "#EDF0F5", "border": "#EDF0F5", "emptyBackground": "transparent", - "iconAlign": "left", + "iconAlign": "right", "minHeight": 64, "minValueFontSize": 12, "nonFiniteText": "N/A", diff --git a/x-pack/plugins/observability_solution/uptime/server/legacy_uptime/lib/adapters/framework/adapter_types.ts b/x-pack/plugins/observability_solution/uptime/server/legacy_uptime/lib/adapters/framework/adapter_types.ts index 6f7dc02299b7d..9c20ff432aa7c 100644 --- a/x-pack/plugins/observability_solution/uptime/server/legacy_uptime/lib/adapters/framework/adapter_types.ts +++ b/x-pack/plugins/observability_solution/uptime/server/legacy_uptime/lib/adapters/framework/adapter_types.ts @@ -16,7 +16,7 @@ import { TaskManagerSetupContract, TaskManagerStartContract, } from '@kbn/task-manager-plugin/server'; -import { PluginSetupContract } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { MlPluginSetup as MlSetup } from '@kbn/ml-plugin/server'; import { RuleRegistryPluginSetupContract } from '@kbn/rule-registry-plugin/server'; import { SecurityPluginStart } from '@kbn/security-plugin/server'; @@ -50,7 +50,7 @@ export interface UptimeServerSetup { } export interface UptimeCorePluginsSetup { - features: PluginSetupContract; + features: FeaturesPluginSetup; alerting: any; observability: ObservabilityPluginSetup; usageCollection: UsageCollectionSetup; diff --git a/x-pack/plugins/osquery/cypress/e2e/roles/alert_test.cy.ts b/x-pack/plugins/osquery/cypress/e2e/roles/alert_test.cy.ts index 718c2f32fd581..b332951b1a444 100644 --- a/x-pack/plugins/osquery/cypress/e2e/roles/alert_test.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/roles/alert_test.cy.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { disableNewFeaturesTours } from '../../tasks/navigation'; import { initializeDataViews } from '../../tasks/login'; import { checkResults, clickRuleName, submitQuery } from '../../tasks/live_query'; import { loadRule, cleanupRule } from '../../tasks/api_fixtures'; @@ -26,7 +27,9 @@ describe('Alert Test', { tags: ['@ess'] }, () => { beforeEach(() => { cy.login(ServerlessRoleName.T1_ANALYST); - cy.visit('/app/security/rules'); + cy.visit('/app/security/rules', { + onBeforeLoad: (win) => disableNewFeaturesTours(win), + }); clickRuleName(ruleName); cy.getBySel('expand-event').first().click({ force: true }); diff --git a/x-pack/plugins/osquery/cypress/tasks/live_query.ts b/x-pack/plugins/osquery/cypress/tasks/live_query.ts index 4c05e2bbc98fe..0d7d8043ca2c3 100644 --- a/x-pack/plugins/osquery/cypress/tasks/live_query.ts +++ b/x-pack/plugins/osquery/cypress/tasks/live_query.ts @@ -5,9 +5,10 @@ * 2.0. */ +import { disableNewFeaturesTours } from './navigation'; import { getAdvancedButton } from '../screens/integrations'; -import { LIVE_QUERY_EDITOR, OSQUERY_FLYOUT_BODY_EDITOR } from '../screens/live_query'; import { ServerlessRoleName } from '../support/roles'; +import { LIVE_QUERY_EDITOR, OSQUERY_FLYOUT_BODY_EDITOR } from '../screens/live_query'; import { waitForAlertsToPopulate } from '../../../../test/security_solution_cypress/cypress/tasks/create_new_rule'; export const DEFAULT_QUERY = 'select * from processes;'; @@ -118,7 +119,9 @@ export const toggleRuleOffAndOn = (ruleName: string) => { export const loadRuleAlerts = (ruleName: string) => { cy.login(ServerlessRoleName.SOC_MANAGER); - cy.visit('/app/security/rules'); + cy.visit('/app/security/rules', { + onBeforeLoad: (win) => disableNewFeaturesTours(win), + }); clickRuleName(ruleName); waitForAlertsToPopulate(); }; diff --git a/x-pack/plugins/osquery/cypress/tasks/login.ts b/x-pack/plugins/osquery/cypress/tasks/login.ts index 89dab4ca72e56..38d71318d01f9 100644 --- a/x-pack/plugins/osquery/cypress/tasks/login.ts +++ b/x-pack/plugins/osquery/cypress/tasks/login.ts @@ -5,12 +5,15 @@ * 2.0. */ +import { disableNewFeaturesTours } from './navigation'; import { ServerlessRoleName } from '../support/roles'; // Login as a SOC_MANAGER to properly initialize Security Solution App export const initializeDataViews = () => { cy.login(ServerlessRoleName.SOC_MANAGER); - cy.visit('/app/security/alerts'); + cy.visit('/app/security/alerts', { + onBeforeLoad: (win) => disableNewFeaturesTours(win), + }); cy.getBySel('globalLoadingIndicator').should('exist'); cy.getBySel('globalLoadingIndicator').should('not.exist'); cy.getBySel('manage-alert-detection-rules').should('exist'); diff --git a/x-pack/plugins/osquery/server/types.ts b/x-pack/plugins/osquery/server/types.ts index ac43d8818d62a..63e37f3770f48 100644 --- a/x-pack/plugins/osquery/server/types.ts +++ b/x-pack/plugins/osquery/server/types.ts @@ -13,7 +13,7 @@ import type { } from '@kbn/data-plugin/server'; import type { FleetStartContract } from '@kbn/fleet-plugin/server'; -import type { PluginSetupContract } from '@kbn/features-plugin/server'; +import type { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import type { SecurityPluginStart } from '@kbn/security-plugin/server'; import type { TaskManagerSetupContract as TaskManagerPluginSetup, @@ -36,7 +36,7 @@ export interface SetupPlugins { actions: ActionsPlugin['setup']; cases: CasesServerSetup; data: DataPluginSetup; - features: PluginSetupContract; + features: FeaturesPluginSetup; security: SecurityPluginStart; taskManager?: TaskManagerPluginSetup; telemetry?: TelemetryPluginSetup; diff --git a/x-pack/plugins/remote_clusters/server/types.ts b/x-pack/plugins/remote_clusters/server/types.ts index 8c1711e189c34..5e1f50f6447c1 100644 --- a/x-pack/plugins/remote_clusters/server/types.ts +++ b/x-pack/plugins/remote_clusters/server/types.ts @@ -7,7 +7,7 @@ import { IRouter } from '@kbn/core/server'; -import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { LicensingPluginSetup } from '@kbn/licensing-plugin/server'; import { CloudSetup } from '@kbn/cloud-plugin/server'; diff --git a/x-pack/plugins/reporting/server/core.ts b/x-pack/plugins/reporting/server/core.ts index b5f0f8b977eb6..794cb5180ea09 100644 --- a/x-pack/plugins/reporting/server/core.ts +++ b/x-pack/plugins/reporting/server/core.ts @@ -25,7 +25,7 @@ import type { } from '@kbn/core/server'; import type { PluginStart as DataPluginStart } from '@kbn/data-plugin/server'; import type { DiscoverServerPluginStart } from '@kbn/discover-plugin/server'; -import type { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import type { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import type { FieldFormatsStart } from '@kbn/field-formats-plugin/server'; import type { LicensingPluginStart } from '@kbn/licensing-plugin/server'; import type { ReportingServerInfo } from '@kbn/reporting-common/types'; diff --git a/x-pack/plugins/reporting/server/features.ts b/x-pack/plugins/reporting/server/features.ts index 45666e2b2460d..7c87f19ca011a 100644 --- a/x-pack/plugins/reporting/server/features.ts +++ b/x-pack/plugins/reporting/server/features.ts @@ -7,7 +7,7 @@ import { DEFAULT_APP_CATEGORIES, type Logger } from '@kbn/core/server'; import { i18n } from '@kbn/i18n'; -import type { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import type { FeaturesPluginSetup } from '@kbn/features-plugin/server'; interface FeatureRegistrationOpts { features: FeaturesPluginSetup; diff --git a/x-pack/plugins/reporting/server/plugin.test.ts b/x-pack/plugins/reporting/server/plugin.test.ts index ac4dcf1bf12c4..de576fe95d006 100644 --- a/x-pack/plugins/reporting/server/plugin.test.ts +++ b/x-pack/plugins/reporting/server/plugin.test.ts @@ -25,7 +25,7 @@ import { ReportingPlugin } from './plugin'; import { createMockPluginSetup, createMockPluginStart } from './test_helpers'; import type { ReportingSetupDeps } from './types'; import { ExportTypesRegistry } from '@kbn/reporting-server/export_types_registry'; -import { PluginSetupContract as FeaturesPluginSetupContract } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; const sleep = (time: number) => new Promise((r) => setTimeout(r, time)); @@ -38,7 +38,7 @@ describe('Reporting Plugin', () => { let pluginStart: ReportingInternalStart; let logger: jest.Mocked; let plugin: ReportingPlugin; - let featuresSetup: jest.Mocked; + let featuresSetup: jest.Mocked; beforeEach(async () => { jest.clearAllMocks(); diff --git a/x-pack/plugins/reporting/server/types.ts b/x-pack/plugins/reporting/server/types.ts index 0c744a513ebac..40415a3aaacf4 100644 --- a/x-pack/plugins/reporting/server/types.ts +++ b/x-pack/plugins/reporting/server/types.ts @@ -9,7 +9,7 @@ import { CustomRequestHandlerContext } from '@kbn/core-http-request-handler-cont import { IRouter } from '@kbn/core-http-server'; import type { DataPluginStart } from '@kbn/data-plugin/server/plugin'; import type { DiscoverServerPluginStart } from '@kbn/discover-plugin/server'; -import type { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import type { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import type { FieldFormatsStart } from '@kbn/field-formats-plugin/server'; import type { LicensingPluginStart } from '@kbn/licensing-plugin/server'; import type { UrlOrUrlLocatorTuple } from '@kbn/reporting-common/types'; diff --git a/x-pack/plugins/rollup/server/types.ts b/x-pack/plugins/rollup/server/types.ts index 29d2fe2e99771..cb3f9b37541a9 100644 --- a/x-pack/plugins/rollup/server/types.ts +++ b/x-pack/plugins/rollup/server/types.ts @@ -11,7 +11,7 @@ import { VisTypeTimeseriesSetup } from '@kbn/vis-type-timeseries-plugin/server'; import { getCapabilitiesForRollupIndices } from '@kbn/data-plugin/server'; import { IndexManagementPluginSetup } from '@kbn/index-management-plugin/server'; -import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { DataViewsServerPluginSetup } from '@kbn/data-views-plugin/server'; import { PluginSetup as DataPluginSetup } from '@kbn/data-plugin/server'; import { LicensingPluginSetup } from '@kbn/licensing-plugin/server'; diff --git a/x-pack/plugins/saved_objects_tagging/server/plugin.ts b/x-pack/plugins/saved_objects_tagging/server/plugin.ts index f62d84f5742e9..e0e65c522b5eb 100644 --- a/x-pack/plugins/saved_objects_tagging/server/plugin.ts +++ b/x-pack/plugins/saved_objects_tagging/server/plugin.ts @@ -6,7 +6,7 @@ */ import { CoreSetup, CoreStart, Plugin } from '@kbn/core/server'; -import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server'; import { SecurityPluginSetup, SecurityPluginStart } from '@kbn/security-plugin/server'; import { savedObjectsTaggingFeature } from './features'; diff --git a/x-pack/plugins/search_connectors/common/connectors.ts b/x-pack/plugins/search_connectors/common/connectors.ts index 647e1b3b6d266..a91dc9b0bd08c 100644 --- a/x-pack/plugins/search_connectors/common/connectors.ts +++ b/x-pack/plugins/search_connectors/common/connectors.ts @@ -334,7 +334,7 @@ export const CONNECTOR_DEFINITIONS: ConnectorServerSideDefinition[] = [ } ), iconPath: 'notion.svg', - isBeta: true, + isBeta: false, isNative: true, keywords: ['notion', 'connector'], name: i18n.translate('searchConnectorsPlugin.content.nativeConnectors.notion.name', { @@ -595,7 +595,7 @@ export const CONNECTOR_DEFINITIONS: ConnectorServerSideDefinition[] = [ ), iconPath: 'sharepoint_server.svg', isBeta: true, - isNative: false, + isNative: true, isTechPreview: false, keywords: ['sharepoint', 'cloud', 'connector'], name: i18n.translate('searchConnectorsPlugin.content.nativeConnectors.sharepointServer.name', { diff --git a/x-pack/plugins/security/server/authorization/app_authorization.test.ts b/x-pack/plugins/security/server/authorization/app_authorization.test.ts index b64226e8ecd06..159b5079cad62 100644 --- a/x-pack/plugins/security/server/authorization/app_authorization.test.ts +++ b/x-pack/plugins/security/server/authorization/app_authorization.test.ts @@ -12,7 +12,7 @@ import { loggingSystemMock, } from '@kbn/core/server/mocks'; import type { - PluginSetupContract as FeaturesSetupContract, + FeaturesPluginSetup as FeaturesSetupContract, KibanaFeature, } from '@kbn/features-plugin/server'; import { featuresPluginMock } from '@kbn/features-plugin/server/mocks'; diff --git a/x-pack/plugins/security/server/authorization/app_authorization.ts b/x-pack/plugins/security/server/authorization/app_authorization.ts index d37d2ec2f37ad..92335ec50f58f 100644 --- a/x-pack/plugins/security/server/authorization/app_authorization.ts +++ b/x-pack/plugins/security/server/authorization/app_authorization.ts @@ -6,7 +6,7 @@ */ import type { HttpServiceSetup, Logger } from '@kbn/core/server'; -import type { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import type { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import type { AuthorizationServiceSetup } from '@kbn/security-plugin-types-server'; class ProtectedApplications { diff --git a/x-pack/plugins/security/server/authorization/authorization_service.tsx b/x-pack/plugins/security/server/authorization/authorization_service.tsx index 09a13e310a041..a926ee4d364b0 100644 --- a/x-pack/plugins/security/server/authorization/authorization_service.tsx +++ b/x-pack/plugins/security/server/authorization/authorization_service.tsx @@ -22,8 +22,8 @@ import type { } from '@kbn/core/server'; import type { Capabilities as UICapabilities } from '@kbn/core/types'; import type { - PluginSetupContract as FeaturesPluginSetup, - PluginStartContract as FeaturesPluginStart, + FeaturesPluginSetup as FeaturesPluginSetup, + FeaturesPluginStart as FeaturesPluginStart, } from '@kbn/features-plugin/server'; import type { AuthorizationMode, diff --git a/x-pack/plugins/security/server/authorization/privileges/privileges.ts b/x-pack/plugins/security/server/authorization/privileges/privileges.ts index ee1901520df85..4295ae7c89bb4 100644 --- a/x-pack/plugins/security/server/authorization/privileges/privileges.ts +++ b/x-pack/plugins/security/server/authorization/privileges/privileges.ts @@ -11,10 +11,7 @@ import type { FeatureKibanaPrivileges, FeatureKibanaPrivilegesReference, } from '@kbn/features-plugin/common'; -import type { - PluginSetupContract as FeaturesPluginSetup, - KibanaFeature, -} from '@kbn/features-plugin/server'; +import type { FeaturesPluginSetup, KibanaFeature } from '@kbn/features-plugin/server'; import { featurePrivilegeBuilderFactory } from './feature_privilege_builder'; import type { SecurityLicense } from '../../../common'; diff --git a/x-pack/plugins/security/server/plugin.ts b/x-pack/plugins/security/server/plugin.ts index a500454f98fa9..b6054478cc2c4 100644 --- a/x-pack/plugins/security/server/plugin.ts +++ b/x-pack/plugins/security/server/plugin.ts @@ -18,10 +18,7 @@ import type { Plugin, PluginInitializerContext, } from '@kbn/core/server'; -import type { - PluginSetupContract as FeaturesPluginSetup, - PluginStartContract as FeaturesPluginStart, -} from '@kbn/features-plugin/server'; +import type { FeaturesPluginSetup, FeaturesPluginStart } from '@kbn/features-plugin/server'; import type { LicensingPluginSetup, LicensingPluginStart } from '@kbn/licensing-plugin/server'; import type { AuditServiceSetup, diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees_route.schema.yaml index 739386d637abd..b4b5e858672dd 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/alert_assignees/set_alert_assignees_route.schema.yaml @@ -4,12 +4,15 @@ info: version: '2023-10-31' paths: /api/detection_engine/signals/assignees: - summary: Assigns users to alerts post: x-labels: [ess, serverless] x-codegen-enabled: true operationId: SetAlertAssignees - description: Assigns users to alerts. + summary: Assign and unassign users from detection alerts + description: | + Assign users to detection alerts, and unassign them from alerts. + > info + > You cannot add and remove the same assignee in the same request. requestBody: required: true content: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/alert_tags/set_alert_tags/set_alert_tags.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/alert_tags/set_alert_tags/set_alert_tags.schema.yaml index ca2c93b88b25e..97833e368ab16 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/alert_tags/set_alert_tags/set_alert_tags.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/alert_tags/set_alert_tags/set_alert_tags.schema.yaml @@ -8,7 +8,11 @@ paths: x-labels: [serverless, ess] operationId: ManageAlertTags x-codegen-enabled: true - summary: Manage alert tags for a one or more alerts + summary: Add and remove detection alert tags + description: | + And tags to detection alerts, and remove them from alerts. + > info + > You cannot add and remove the same alert tag in the same request. tags: - Alerts API requestBody: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/response_actions.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/response_actions.gen.ts index d9bed47ea7766..234b90373f5b5 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/response_actions.gen.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/response_actions.gen.ts @@ -36,7 +36,7 @@ export const OsqueryQuery = z.object({ */ id: z.string(), /** - * Query to execute + * Query to run */ query: z.string(), ecs_mapping: EcsMapping.optional(), diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/response_actions.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/response_actions.schema.yaml index 751a1efee8fa8..3666b9e4e063b 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/response_actions.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/response_actions.schema.yaml @@ -34,7 +34,7 @@ components: description: Query ID query: type: string - description: Query to execute + description: Query to run ecs_mapping: $ref: '#/components/schemas/EcsMapping' version: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.gen.ts index dadb6bfa4165d..1573d58965db6 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.gen.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.gen.ts @@ -99,7 +99,7 @@ export type RuleInterval = z.infer; export const RuleInterval = z.string(); /** - * Time from which data is analyzed each time the rule executes, using a date math range. For example, now-4200s means the rule analyzes data from 70 minutes before its start time. Defaults to now-6m (analyzes data from 6 minutes before the start time). + * Time from which data is analyzed each time the rule runs, using a date math range. For example, now-4200s means the rule analyzes data from 70 minutes before its start time. Defaults to now-6m (analyzes data from 6 minutes before the start time). */ export type RuleIntervalFrom = z.infer; export const RuleIntervalFrom = z.string().superRefine(isValidDateMath); @@ -454,7 +454,7 @@ export const InvestigationFields = z.object({ }); /** - * Defines the interval on which a rule's actions are executed. + * Defines how often rule actions are taken. */ export type RuleActionThrottle = z.infer; export const RuleActionThrottle = z.union([ diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.schema.yaml index b2d72a561e46c..795ed2d22da17 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.schema.yaml @@ -92,7 +92,7 @@ components: RuleIntervalFrom: type: string - description: Time from which data is analyzed each time the rule executes, using a date math range. For example, now-4200s means the rule analyzes data from 70 minutes before its start time. Defaults to now-6m (analyzes data from 6 minutes before the start time). + description: Time from which data is analyzed each time the rule runs, using a date math range. For example, now-4200s means the rule analyzes data from 70 minutes before its start time. Defaults to now-6m (analyzes data from 6 minutes before the start time). format: date-math RuleIntervalTo: @@ -470,7 +470,7 @@ components: - field_names RuleActionThrottle: - description: Defines the interval on which a rule's actions are executed. + description: Defines how often rule actions are taken. oneOf: - type: string enum: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/threat_match_attributes.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/threat_match_attributes.gen.ts index c58382964eae9..32d0c6e2e68b4 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/threat_match_attributes.gen.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/threat_match_attributes.gen.ts @@ -19,7 +19,7 @@ import { z } from 'zod'; import { NonEmptyString } from '../../../../model/primitives.gen'; /** - * Query to execute + * Query to run */ export type ThreatQuery = z.infer; export const ThreatQuery = z.string(); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/threat_match_attributes.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/threat_match_attributes.schema.yaml index de43ecfeb073d..6b9f8805d5782 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/threat_match_attributes.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/threat_match_attributes.schema.yaml @@ -8,7 +8,7 @@ components: schemas: ThreatQuery: type: string - description: Query to execute + description: Query to run ThreatMapping: type: array diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/get_prebuilt_rules_and_timelines_status/get_prebuilt_rules_and_timelines_status_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/get_prebuilt_rules_and_timelines_status/get_prebuilt_rules_and_timelines_status_route.schema.yaml index 92b82e9d1e849..bc44026806f6f 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/get_prebuilt_rules_and_timelines_status/get_prebuilt_rules_and_timelines_status_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/get_prebuilt_rules_and_timelines_status/get_prebuilt_rules_and_timelines_status_route.schema.yaml @@ -8,7 +8,8 @@ paths: x-labels: [ess] x-codegen-enabled: true operationId: GetPrebuiltRulesAndTimelinesStatus - summary: Get the status of Elastic prebuilt rules + summary: Retrieve the status of prebuilt detection rules and Timelines + description: Retrieve the status of all Elastic prebuilt detection rules and Timelines. tags: - Prebuilt Rules API responses: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/install_prebuilt_rules_and_timelines/install_prebuilt_rules_and_timelines_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/install_prebuilt_rules_and_timelines/install_prebuilt_rules_and_timelines_route.schema.yaml index ab27c71c4ef33..171070aa5e2d9 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/install_prebuilt_rules_and_timelines/install_prebuilt_rules_and_timelines_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/install_prebuilt_rules_and_timelines/install_prebuilt_rules_and_timelines_route.schema.yaml @@ -8,7 +8,8 @@ paths: x-labels: [ess] x-codegen-enabled: true operationId: InstallPrebuiltRulesAndTimelines - summary: Installs all Elastic prebuilt rules and timelines + summary: Install prebuilt detection rules and Timelines + description: Install and update all Elastic prebuilt detection rules and Timelines. tags: - Prebuilt Rules API responses: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.gen.ts index b9750fd7eb06d..ff503d0b0d4e7 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.gen.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.gen.ts @@ -241,7 +241,7 @@ export const BulkActionEditPayloadSchedule = z.object({ type: z.literal('set_schedule'), value: z.object({ /** - * Interval in which the rule is executed + * Interval in which the rule runs. For example, `"1h"` means the rule runs every hour. */ interval: z.string().regex(/^[1-9]\d*[smh]$/), /** diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.schema.yaml index 184f4ec9825b6..2df8c770546e8 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.schema.yaml @@ -8,8 +8,8 @@ paths: x-labels: [ess, serverless] x-codegen-enabled: true operationId: PerformBulkAction - summary: Applies a bulk action to multiple rules - description: The bulk action is applied to all rules that match the filter or to the list of rules by their IDs. + summary: Apply a bulk action to detection rules + description: Apply a bulk action, such as bulk edit, duplicate, or delete, to multiple detection rules. The bulk action is applied to all rules that match the query or to the rules listed by their IDs. tags: - Bulk API parameters: @@ -366,7 +366,7 @@ components: properties: interval: type: string - description: Interval in which the rule is executed + description: Interval in which the rule runs. For example, `"1h"` means the rule runs every hour. pattern: '^[1-9]\d*[smh]$' # any number except zero followed by one of the suffixes 's', 'm', 'h' example: '1h' lookback: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.schema.yaml index 127ad9784988d..8b024946bc220 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.schema.yaml @@ -9,7 +9,8 @@ paths: x-codegen-enabled: true operationId: BulkCreateRules deprecated: true - description: Creates new detection rules in bulk. + summary: Create multiple detection rules + description: Create new detection rules in bulk. tags: - Bulk API requestBody: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_delete_rules/bulk_delete_rules_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_delete_rules/bulk_delete_rules_route.schema.yaml index 0229f28a0941d..2a7ac4cf1d1e1 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_delete_rules/bulk_delete_rules_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_delete_rules/bulk_delete_rules_route.schema.yaml @@ -9,7 +9,8 @@ paths: x-codegen-enabled: true operationId: BulkDeleteRules deprecated: true - description: Deletes multiple rules. + summary: Delete multiple detection rules + description: Delete detection rules in bulk. tags: - Bulk API requestBody: @@ -39,20 +40,20 @@ paths: application/json: schema: oneOf: - - $ref: '../../../model/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../model/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + - $ref: '../../../../model/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../model/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' 401: description: Unsuccessful authentication response content: application/json: schema: - $ref: '../../../model/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + $ref: '../../../../model/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' 500: description: Internal server error response content: application/json: schema: - $ref: '../../../model/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + $ref: '../../../../model/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' post: x-labels: [ess] @@ -89,17 +90,17 @@ paths: application/json: schema: oneOf: - - $ref: '../../../model/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../model/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + - $ref: '../../../../model/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../../../model/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' 401: description: Unsuccessful authentication response content: application/json: schema: - $ref: '../../../model/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + $ref: '../../../../model/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' 500: description: Internal server error response content: application/json: schema: - $ref: '../../../model/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + $ref: '../../../../model/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.schema.yaml index 65bd0e1a4ac36..8c414965385f4 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.schema.yaml @@ -7,9 +7,10 @@ paths: patch: x-labels: [ess] x-codegen-enabled: true + summary: Patch multiple detection rules operationId: BulkPatchRules deprecated: true - description: Updates multiple rules using the `PATCH` method. + description: Update specific fields of existing detection rules using the `rule_id` or `id` field. tags: - Bulk API requestBody: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.schema.yaml index 37241035439d3..841abbaea8fcd 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.schema.yaml @@ -9,7 +9,11 @@ paths: x-codegen-enabled: true operationId: BulkUpdateRules deprecated: true - description: Updates multiple rules using the `PUT` method. + summary: Update multiple detection rules + description: | + Update multiple detection rules using the `rule_id` or `id` field. The original rules are replaced, and all unspecified fields are deleted. + > info + > You cannot modify the `id` or `rule_id` values. tags: - Bulk API requestBody: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/create_rule/create_rule_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/create_rule/create_rule_route.schema.yaml index a5071837af2cf..d3e3dca94d004 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/create_rule/create_rule_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/create_rule/create_rule_route.schema.yaml @@ -8,7 +8,8 @@ paths: x-labels: [ess, serverless] x-codegen-enabled: true operationId: CreateRule - description: Create a single detection rule + summary: Create a detection rule + description: Create a new detection rule. tags: - Rules API requestBody: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/delete_rule/delete_rule_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/delete_rule/delete_rule_route.schema.yaml index b6ef8a444eb55..78d34bc2c5699 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/delete_rule/delete_rule_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/delete_rule/delete_rule_route.schema.yaml @@ -8,7 +8,8 @@ paths: x-labels: [ess, serverless] x-codegen-enabled: true operationId: DeleteRule - description: Deletes a single rule using the `rule_id` or `id` field. + summary: Delete a detection rule + description: Delete a detection rule using the `rule_id` or `id` field. tags: - Rules API parameters: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.schema.yaml index aec02102bcca4..1ef40635f3305 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.schema.yaml @@ -8,7 +8,8 @@ paths: x-labels: [ess, serverless] x-codegen-enabled: true operationId: PatchRule - description: Patch a single rule + summary: Patch a detection rule + description: Update specific fields of an existing detection rule using the `rule_id` or `id` field. tags: - Rules API requestBody: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/read_rule/read_rule_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/read_rule/read_rule_route.schema.yaml index 817579eb8c27e..b22de6af6a9b8 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/read_rule/read_rule_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/read_rule/read_rule_route.schema.yaml @@ -8,7 +8,8 @@ paths: x-labels: [ess, serverless] x-codegen-enabled: true operationId: ReadRule - description: Read a single rule + summary: Retrieve a detection rule + description: Retrieve a detection rule using the `rule_id` or `id` field. tags: - Rules API parameters: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/update_rule/update_rule_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/update_rule/update_rule_route.schema.yaml index de82265ca3379..4450b0ec1f7dc 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/update_rule/update_rule_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/update_rule/update_rule_route.schema.yaml @@ -8,7 +8,11 @@ paths: x-labels: [ess, serverless] x-codegen-enabled: true operationId: UpdateRule - description: Update a single rule + summary: Update a detection rule + description: | + Update a detection rule using the `rule_id` or `id` field. The original rule is replaced, and all unspecified fields are deleted. + > info + > You cannot modify the `id` or `rule_id` values. tags: - Rules API requestBody: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/export_rules/export_rules_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/export_rules/export_rules_route.schema.yaml index 0a88075abb158..cae20f30e2c73 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/export_rules/export_rules_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/export_rules/export_rules_route.schema.yaml @@ -4,13 +4,17 @@ info: version: '2023-10-31' paths: /api/detection_engine/rules/_export: - summary: Exports rules to an `.ndjson` file post: x-labels: [ess, serverless] x-codegen-enabled: true operationId: ExportRules - summary: Export rules - description: Exports rules to an `.ndjson` file. The following configuration items are also included in the `.ndjson` file - Actions, Exception lists. Prebuilt rules cannot be exported. + summary: Export detection rules + description: | + Export detection rules to an `.ndjson` file. The following configuration items are also included in the `.ndjson` file: + - Actions + - Exception lists + > info + > You cannot export prebuilt rules. tags: - Import/Export API parameters: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/find_rules_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/find_rules_route.schema.yaml index 4f27662e37bfd..3be5404bae74f 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/find_rules_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/find_rules/find_rules_route.schema.yaml @@ -8,7 +8,8 @@ paths: x-labels: [ess, serverless] x-codegen-enabled: true operationId: FindRules - description: Finds rules that match the given query. + summary: List all detection rules + description: Retrieve a paginated list of detection rules. By default, the first page is returned, with 20 results per page. tags: - Rules API parameters: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/import_rules_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/import_rules_route.schema.yaml index 9056fcea04bca..5d0b0c9d857bd 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/import_rules_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/import_rules_route.schema.yaml @@ -4,13 +4,15 @@ info: version: '2023-10-31' paths: /api/detection_engine/rules/_import: - summary: Imports rules from an `.ndjson` file post: x-labels: [ess, serverless] x-codegen-enabled: true operationId: ImportRules - summary: Import rules - description: Imports rules from an `.ndjson` file, including actions and exception lists. + summary: Import detection rules + description: | + Import detection rules from an `.ndjson` file, including actions and exception lists. The request must include: + - The `Content-Type: multipart/form-data` HTTP header. + - A link to the `.ndjson` file containing the rules. tags: - Import/Export API requestBody: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/read_tags/read_tags_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/read_tags/read_tags_route.schema.yaml index 0a9d622dd2d4a..84ebd06052054 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/read_tags/read_tags_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/read_tags/read_tags_route.schema.yaml @@ -4,12 +4,12 @@ info: version: '2023-10-31' paths: /api/detection_engine/tags: - summary: Aggregates and returns rule tags get: x-labels: [ess, serverless] x-codegen-enabled: true operationId: ReadTags - summary: Aggregates and returns all unique tags from all rules + summary: List all detection rule tags + description: List all unique tags from all detection rules. tags: - Tags API responses: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_preview/rule_preview.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_preview/rule_preview.schema.yaml index 933dccc0b8d65..1d65d6b4e037e 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_preview/rule_preview.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_preview/rule_preview.schema.yaml @@ -67,20 +67,20 @@ paths: application/json: schema: oneOf: - - $ref: '../../../model/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' - - $ref: '../../../model/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + - $ref: '../../model/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + - $ref: '../../model/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' 401: description: Unsuccessful authentication response content: application/json: schema: - $ref: '../../../model/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' + $ref: '../../model/error_responses.schema.yaml#/components/schemas/PlatformErrorResponse' 500: description: Internal server error response content: application/json: schema: - $ref: '../../../model/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' + $ref: '../../model/error_responses.schema.yaml#/components/schemas/SiemErrorResponse' components: schemas: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals/query_signals/query_signals_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/signals/query_signals/query_signals_route.schema.yaml index cd70e4b0c4071..00061cf50c60d 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/signals/query_signals/query_signals_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/signals/query_signals/query_signals_route.schema.yaml @@ -8,7 +8,8 @@ paths: x-labels: [serverless, ess] operationId: SearchAlerts x-codegen-enabled: true - summary: Find and/or aggregate detection alerts that match the given query + summary: Find and/or aggregate detection alerts + description: Find and/or aggregate detection alerts that match the given query. tags: - Alerts API requestBody: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals/set_signal_status/set_signals_status_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/signals/set_signal_status/set_signals_status_route.schema.yaml index 29ee065c77e6b..fe514c4dafe2e 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/signals/set_signal_status/set_signals_status_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/signals/set_signal_status/set_signals_status_route.schema.yaml @@ -8,7 +8,8 @@ paths: x-labels: [serverless, ess] operationId: SetAlertsStatus x-codegen-enabled: true - summary: Sets the status of one or more alerts + summary: Set a detection alert status + description: Set the status of one or more detection alerts. tags: - Alerts API requestBody: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/create_signals_migration/create_signals_migration.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/create_signals_migration/create_signals_migration.schema.yaml index 26204ea0d6195..52178537d6363 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/create_signals_migration/create_signals_migration.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/create_signals_migration/create_signals_migration.schema.yaml @@ -8,7 +8,10 @@ paths: x-labels: [ess] operationId: CreateAlertsMigration x-codegen-enabled: true - summary: Initiates an alerts migration + summary: Initiate a detection alert migration + description: | + Initiate a migration of detection alerts. + Migrations are initiated per index. While the process is neither destructive nor interferes with existing data, it may be resource-intensive. As such, it is recommended that you plan your migrations accordingly. tags: - Alerts migration API requestBody: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/delete_signals_migration/delete_signals_migration.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/delete_signals_migration/delete_signals_migration.schema.yaml index 7b8136f3702cf..8aa36d8496d09 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/delete_signals_migration/delete_signals_migration.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/delete_signals_migration/delete_signals_migration.schema.yaml @@ -8,11 +8,13 @@ paths: x-labels: [ess] operationId: AlertsMigrationCleanup x-codegen-enabled: true - summary: Performs alerts migration(s) cleanup + summary: Clean up detection alert migrations description: | Migrations favor data integrity over shard size. Consequently, unused or orphaned indices are artifacts of the migration process. A successful migration will result in both the old and new indices being present. - As such, the old, orphaned index can (and likely should) be deleted. While you can delete these indices manually, + As such, the old, orphaned index can (and likely should) be deleted. + + While you can delete these indices manually, the endpoint accomplishes this task by applying a deletion policy to the relevant index, causing it to be deleted after 30 days. It also deletes other artifacts specific to the migration implementation. tags: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/finalize_signals_migration/finalize_signals_migration.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/finalize_signals_migration/finalize_signals_migration.schema.yaml index 3654973f9de7e..d36df73832530 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/finalize_signals_migration/finalize_signals_migration.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/finalize_signals_migration/finalize_signals_migration.schema.yaml @@ -8,9 +8,9 @@ paths: x-labels: [ess] operationId: FinalizeAlertsMigration x-codegen-enabled: true - summary: Finalizes alerts migration(s) + summary: Finalize detection alert migrations description: | - The finalization endpoint replaces the original index's alias with the successfully migrated index's alias. + Finalize successful migrations of detection alerts. This replaces the original index's alias with the successfully migrated index's alias. The endpoint is idempotent; therefore, it can safely be used to poll a given migration and, upon completion, finalize it. tags: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/get_signals_migration_status/get_signals_migration_status.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/get_signals_migration_status/get_signals_migration_status.schema.yaml index b480b4374498b..64eafd09f65d7 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/get_signals_migration_status/get_signals_migration_status.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/get_signals_migration_status/get_signals_migration_status.schema.yaml @@ -8,7 +8,8 @@ paths: x-labels: [ess] operationId: GetAlertsMigrationStatus x-codegen-enabled: true - summary: Returns an alerts migration status + summary: Retrieve the status of detection alert migrations + description: Retrieve indices that contain detection alerts of a particular age, along with migration information for each of those indices. tags: - Alerts migration API parameters: diff --git a/x-pack/plugins/security_solution/common/endpoint/data_generators/sentinelone_data_generator.ts b/x-pack/plugins/security_solution/common/endpoint/data_generators/sentinelone_data_generator.ts index 3870710456ad0..526064dd9daae 100644 --- a/x-pack/plugins/security_solution/common/endpoint/data_generators/sentinelone_data_generator.ts +++ b/x-pack/plugins/security_solution/common/endpoint/data_generators/sentinelone_data_generator.ts @@ -14,6 +14,9 @@ import type { SentinelOneGetActivitiesResponse, SentinelOneGetAgentsResponse, SentinelOneActivityRecord, + SentinelOneOsType, + SentinelOneGetRemoteScriptStatusApiResponse, + SentinelOneRemoteScriptExecutionStatus, } from '@kbn/stack-connectors-plugin/common/sentinelone/types'; import { EndpointActionGenerator } from './endpoint_action_generator'; import { SENTINEL_ONE_ACTIVITY_INDEX_PATTERN } from '../..'; @@ -26,6 +29,21 @@ import type { } from '../types'; export class SentinelOneDataGenerator extends EndpointActionGenerator { + static readonly scriptExecutionStatusValues: Readonly< + Array + > = Object.freeze([ + 'canceled', + 'completed', + 'created', + 'expired', + 'failed', + 'in_progress', + 'partially_completed', + 'pending', + 'pending_user_action', + 'scheduled', + ]); + generate< TParameters extends EndpointActionDataParameterTypes = EndpointActionDataParameterTypes, TOutputContent extends EndpointActionResponseDataOutput = EndpointActionResponseDataOutput, @@ -368,6 +386,44 @@ export class SentinelOneDataGenerator extends EndpointActionGenerator { errors: null, }; } + + generateSentinelOneApiRemoteScriptStatusResponse( + overrides: Partial = {} + ): SentinelOneGetRemoteScriptStatusApiResponse { + const scriptExecutionStatus: SentinelOneRemoteScriptExecutionStatus = { + accountId: this.seededUUIDv4(), + accountName: 'Elastic', + agentComputerName: this.randomHostname(), + agentId: this.seededUUIDv4(), + agentIsActive: true, + agentIsDecommissioned: false, + agentMachineType: 'server', + agentOsType: this.randomOSFamily() as SentinelOneOsType, + agentUuid: this.seededUUIDv4(), + createdAt: '2024-06-04T15:48:07.183909Z', + description: 'Terminate Processes', + detailedStatus: 'Execution completed successfully', + groupId: '1392053568591146999', + groupName: 'Default Group', + id: this.seededUUIDv4(), + initiatedBy: this.randomUser(), + initiatedById: '1809444483386312727', + parentTaskId: this.seededUUIDv4(), + scriptResultsSignature: '632e6e027', + siteId: '1392053568582758390', + siteName: 'Default site', + status: this.randomChoice(SentinelOneDataGenerator.scriptExecutionStatusValues), + statusCode: 'ok', + statusDescription: 'Completed', + type: 'script_execution', + updatedAt: '2024-06-04T15:49:20.508099Z', + }; + + return { + data: [merge(scriptExecutionStatus, overrides)], + pagination: { totalItems: 1, nextCursor: undefined }, + }; + } } // Activity types from SentinelOne. Values can be retrieved from the SentineOne API at: diff --git a/x-pack/plugins/security_solution/common/endpoint/service/response_actions/is_response_action_supported.ts b/x-pack/plugins/security_solution/common/endpoint/service/response_actions/is_response_action_supported.ts index 61216afeea1ee..928327fc0e28d 100644 --- a/x-pack/plugins/security_solution/common/endpoint/service/response_actions/is_response_action_supported.ts +++ b/x-pack/plugins/security_solution/common/endpoint/service/response_actions/is_response_action_supported.ts @@ -110,7 +110,7 @@ const RESPONSE_ACTIONS_SUPPORT_MAP: SupportMap = { }, manual: { endpoint: true, - sentinel_one: false, + sentinel_one: true, crowdstrike: false, }, }, diff --git a/x-pack/plugins/security_solution/common/endpoint/types/actions.ts b/x-pack/plugins/security_solution/common/endpoint/types/actions.ts index 01da8a39ee723..47556a966280a 100644 --- a/x-pack/plugins/security_solution/common/endpoint/types/actions.ts +++ b/x-pack/plugins/security_solution/common/endpoint/types/actions.ts @@ -9,10 +9,10 @@ import type { TypeOf } from '@kbn/config-schema'; import type { EcsError } from '@elastic/ecs'; import type { BaseFileMetadata, FileCompression, FileJSON } from '@kbn/files-plugin/common'; import type { - ResponseActionBodySchema, - UploadActionApiRequestBody, KillProcessRouteRequestSchema, + ResponseActionBodySchema, SuspendProcessRouteRequestSchema, + UploadActionApiRequestBody, } from '../../api/endpoint'; import type { ActionStatusRequestSchema } from '../../api/endpoint/actions/action_status_route'; import type { NoParametersRequestSchema } from '../../api/endpoint/actions/common/base'; @@ -56,6 +56,7 @@ export interface KillProcessActionOutputContent { command?: string; pid?: number; entity_id?: string; + process_name?: string; } export interface ResponseActionGetFileOutputContent { @@ -135,7 +136,7 @@ export interface LogsEndpointAction< agent: { id: string | string[]; }; - EndpointActions: EndpointActionFields & ActionRequestFields; + EndpointActions: EndpointActionFields & ActionRequestFields; error?: EcsError; user: { id: string; diff --git a/x-pack/plugins/security_solution/common/endpoint/types/sentinel_one.ts b/x-pack/plugins/security_solution/common/endpoint/types/sentinel_one.ts index a15557617d9f0..000292e5b52cb 100644 --- a/x-pack/plugins/security_solution/common/endpoint/types/sentinel_one.ts +++ b/x-pack/plugins/security_solution/common/endpoint/types/sentinel_one.ts @@ -116,6 +116,14 @@ export interface SentinelOneGetFileResponseMeta { filename: string; } +export interface SentinelOneProcessesRequestMeta extends SentinelOneGetFileRequestMeta { + /** + * The Parent Task Is that is executing the kill process action in SentinelOne. + * Used to check on the status of that action + */ + parentTaskId: string; +} + export interface SentinelOneKillProcessRequestMeta extends SentinelOneIsolationRequestMeta { /** * The Parent Task Is that is executing the kill process action in SentinelOne. @@ -123,3 +131,8 @@ export interface SentinelOneKillProcessRequestMeta extends SentinelOneIsolationR */ parentTaskId: string; } + +export interface SentinelOneKillProcessResponseMeta { + /** The SentinelOne task ID associated with the completion of the kill-process action */ + taskId: string; +} diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index 8f6147102c441..6d0ccebbd56bf 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -84,6 +84,9 @@ export const allowedExperimentalValues = Object.freeze({ /** Enables the `kill-process` response action for SentinelOne */ responseActionsSentinelOneKillProcessEnabled: false, + /** Enable the `processes` response actions for SentinelOne */ + responseActionsSentinelOneProcessesEnabled: false, + /** * Enables the ability to send Response actions to Crowdstrike and persist the results * in ES. @@ -121,7 +124,7 @@ export const allowedExperimentalValues = Object.freeze({ assistantModelEvaluation: false, /** - * Enables the Assistant Knowledge Base by default, introduced in `8.15.0`. + * Enables new Knowledge Base Entries features, introduced in `8.15.0`. */ assistantKnowledgeBaseByDefault: false, diff --git a/x-pack/plugins/security_solution/common/guided_onboarding/siem_guide_config.test.ts b/x-pack/plugins/security_solution/common/guided_onboarding/siem_guide_config.test.ts index e1482f19354d9..44abde3f0fc8d 100644 --- a/x-pack/plugins/security_solution/common/guided_onboarding/siem_guide_config.test.ts +++ b/x-pack/plugins/security_solution/common/guided_onboarding/siem_guide_config.test.ts @@ -63,168 +63,4 @@ describe('getSiemGuideConfig', () => { ], }); }); - - it('returns a GuideConfig object with values from the launchDarkly argument when it is passed', () => { - const launchDarkly = { - title: 'Custom Title', - description: 'Custom Description', - docs: 'Custom Docs', - steps: { - add_data: { - title: 'Custom Add Data Title', - description: 'Custom Add Data Description', - }, - rules: { - title: 'Custom Rules Title', - description: 'Custom Rules Description', - manualCompletion: { - title: 'Custom Rules Manual Title', - description: 'Custom Rules Manual Description', - }, - }, - alertsCases: { - title: 'Custom Alerts Cases Title', - description: 'Custom Alerts Cases Description', - manualCompletion: { - title: 'Custom Alerts Cases Manual Title', - description: 'Custom Alerts Cases Manual Description', - }, - }, - }, - }; - const result = getSiemGuideConfig(launchDarkly); - expect(result).toEqual({ - title: launchDarkly.title, - guideName: 'Security', - telemetryId: siemGuideId, - completedGuideRedirectLocation: { - appID: 'securitySolutionUI', - path: '/dashboards', - }, - description: launchDarkly.description, - docs: { - text: launchDarkly.docs, - url: 'https://www.elastic.co/guide/en/security/current/ingest-data.html', - }, - steps: [ - { - id: 'add_data', - title: launchDarkly.steps.add_data.title, - description: { - descriptionText: launchDarkly.steps.add_data.description, - linkUrl: 'https://docs.elastic.co/en/integrations/endpoint', - isLinkExternal: true, - linkText: i18n.LINK_TEXT, - }, - integration: 'endpoint', - location: { - appID: 'integrations', - path: '/detail/endpoint/overview', - }, - }, - { - id: 'rules', - title: launchDarkly.steps.rules.title, - description: launchDarkly.steps.rules.description, - manualCompletion: { - title: launchDarkly.steps.rules.manualCompletion.title, - description: launchDarkly.steps.rules.manualCompletion.description, - }, - location: { - appID: 'securitySolutionUI', - path: '/rules', - }, - }, - { - id: 'alertsCases', - title: launchDarkly.steps.alertsCases.title, - description: launchDarkly.steps.alertsCases.description, - manualCompletion: { - title: launchDarkly.steps.alertsCases.manualCompletion.title, - description: launchDarkly.steps.alertsCases.manualCompletion.description, - }, - location: { - appID: 'securitySolutionUI', - path: '/alerts', - }, - }, - ], - }); - }); - - it('returns a GuideConfig object with values from the launchDarkly argument and default values when some properties are missing', () => { - const launchDarkly = { - steps: { - add_data: { - title: 'Custom Add Data Title', - }, - rules: { - description: 'Custom Rules Description', - }, - alertsCases: { - manualCompletion: { - title: 'Custom Alerts Cases Manual Title', - }, - }, - }, - }; - // Ignore because intentionally passing an incomplete object to test that we handle missing properties - // since there is no validation on the object from LaunchDarkly - // @ts-ignore - const result = getSiemGuideConfig(launchDarkly); - expect(result).toEqual({ - title: defaultGuideTranslations.title, - guideName: 'Security', - telemetryId: siemGuideId, - completedGuideRedirectLocation: { - appID: 'securitySolutionUI', - path: '/dashboards', - }, - description: defaultGuideTranslations.description, - docs: { - text: defaultGuideTranslations.docs, - url: 'https://www.elastic.co/guide/en/security/current/ingest-data.html', - }, - steps: [ - { - id: 'add_data', - title: launchDarkly.steps.add_data.title, - description: { - descriptionText: defaultGuideTranslations.steps.add_data.description, - linkUrl: 'https://docs.elastic.co/en/integrations/endpoint', - isLinkExternal: true, - linkText: i18n.LINK_TEXT, - }, - integration: 'endpoint', - location: { - appID: 'integrations', - path: '/detail/endpoint/overview', - }, - }, - { - id: 'rules', - title: defaultGuideTranslations.steps.rules.title, - description: launchDarkly.steps.rules.description, - location: { - appID: 'securitySolutionUI', - path: '/rules', - }, - manualCompletion: defaultGuideTranslations.steps.rules.manualCompletion, - }, - { - id: 'alertsCases', - title: defaultGuideTranslations.steps.alertsCases.title, - description: defaultGuideTranslations.steps.alertsCases.description, - manualCompletion: { - title: launchDarkly.steps.alertsCases.manualCompletion.title, - description: defaultGuideTranslations.steps.alertsCases.manualCompletion.description, - }, - location: { - appID: 'securitySolutionUI', - path: '/alerts', - }, - }, - ], - }); - }); }); diff --git a/x-pack/plugins/security_solution/common/guided_onboarding/siem_guide_config.ts b/x-pack/plugins/security_solution/common/guided_onboarding/siem_guide_config.ts index 9ee5775d06d62..c28f86ea9535d 100644 --- a/x-pack/plugins/security_solution/common/guided_onboarding/siem_guide_config.ts +++ b/x-pack/plugins/security_solution/common/guided_onboarding/siem_guide_config.ts @@ -38,28 +38,26 @@ export const defaultGuideTranslations = { }, }; -export const getSiemGuideConfig = (launchDarkly = defaultGuideTranslations): GuideConfig => ({ +export const getSiemGuideConfig = (): GuideConfig => ({ // check each launchDarkly property in case data is misformatted - title: launchDarkly.title ?? defaultGuideTranslations.title, + title: defaultGuideTranslations.title, guideName: 'Security', telemetryId: siemGuideId, completedGuideRedirectLocation: { appID: 'securitySolutionUI', path: '/dashboards', }, - description: launchDarkly.description ?? defaultGuideTranslations.description, + description: defaultGuideTranslations.description, docs: { - text: launchDarkly.docs ?? defaultGuideTranslations.docs, + text: defaultGuideTranslations.docs, url: 'https://www.elastic.co/guide/en/security/current/ingest-data.html', }, steps: [ { id: 'add_data', - title: launchDarkly.steps?.add_data?.title ?? defaultGuideTranslations.steps.add_data.title, + title: defaultGuideTranslations.steps.add_data.title, description: { - descriptionText: - launchDarkly.steps?.add_data?.description ?? - defaultGuideTranslations.steps.add_data.description, + descriptionText: defaultGuideTranslations.steps.add_data.description, linkUrl: 'https://docs.elastic.co/en/integrations/endpoint', isLinkExternal: true, linkText: i18n.LINK_TEXT, @@ -72,16 +70,11 @@ export const getSiemGuideConfig = (launchDarkly = defaultGuideTranslations): Gui }, { id: 'rules', - title: launchDarkly.steps?.rules?.title ?? defaultGuideTranslations.steps.rules.title, - description: - launchDarkly.steps?.rules?.description ?? defaultGuideTranslations.steps.rules.description, + title: defaultGuideTranslations.steps.rules.title, + description: defaultGuideTranslations.steps.rules.description, manualCompletion: { - title: - launchDarkly.steps?.rules?.manualCompletion?.title ?? - defaultGuideTranslations.steps.rules.manualCompletion.title, - description: - launchDarkly.steps?.rules?.manualCompletion?.description ?? - defaultGuideTranslations.steps.rules.manualCompletion.description, + title: defaultGuideTranslations.steps.rules.manualCompletion.title, + description: defaultGuideTranslations.steps.rules.manualCompletion.description, }, location: { appID: 'securitySolutionUI', @@ -90,22 +83,15 @@ export const getSiemGuideConfig = (launchDarkly = defaultGuideTranslations): Gui }, { id: 'alertsCases', - title: - launchDarkly.steps?.alertsCases?.title ?? defaultGuideTranslations.steps.alertsCases.title, - description: - launchDarkly.steps?.alertsCases?.description ?? - defaultGuideTranslations.steps.alertsCases.description, + title: defaultGuideTranslations.steps.alertsCases.title, + description: defaultGuideTranslations.steps.alertsCases.description, location: { appID: 'securitySolutionUI', path: '/alerts', }, manualCompletion: { - title: - launchDarkly.steps?.alertsCases?.manualCompletion?.title ?? - defaultGuideTranslations.steps.alertsCases.manualCompletion.title, - description: - launchDarkly.steps?.alertsCases?.manualCompletion?.description ?? - defaultGuideTranslations.steps.alertsCases.manualCompletion.description, + title: defaultGuideTranslations.steps.alertsCases.manualCompletion.title, + description: defaultGuideTranslations.steps.alertsCases.manualCompletion.description, }, }, ], 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 9d96333796a34..46017971df1b0 100644 --- a/x-pack/plugins/security_solution/common/guided_onboarding/translations.ts +++ b/x-pack/plugins/security_solution/common/guided_onboarding/translations.ts @@ -8,11 +8,11 @@ import { i18n } from '@kbn/i18n'; export const TITLE = i18n.translate('xpack.securitySolution.guideConfig.title', { - defaultMessage: 'Detect threats in my data with SIEM', + defaultMessage: 'Detect threats in my data with Security Solution', }); export const DESCRIPTION = i18n.translate('xpack.securitySolution.guideConfig.description', { - defaultMessage: `There are many ways to get your SIEM data into Elastic. In this guide, we'll help you get set up quickly using the Elastic Defend integration.`, + defaultMessage: `Welcome to Elastic Security for SIEM. In this guide, you'll learn how to analyze log and event data, set up threat detection, and respond to threats.`, }); export const DOCS = i18n.translate('xpack.securitySolution.guideConfig.documentationLink', { @@ -29,7 +29,7 @@ export const LINK_TEXT = i18n.translate( export const ADD_DATA_TITLE = i18n.translate( 'xpack.securitySolution.guideConfig.addDataStep.title', { - defaultMessage: 'Add data with Elastic Defend', + defaultMessage: 'Send log and event data to Elastic', } ); @@ -37,7 +37,7 @@ export const ADD_DATA_DESCRIPTION = i18n.translate( 'xpack.securitySolution.guideConfig.addDataStep.description', { defaultMessage: - 'Install Elastic Agent and its Elastic Defend integration on one of your computers to get SIEM data flowing.', + 'Install an agent on one of your computers and configure it with the Elastic Defend integration. With this integration, the agent will be able to collect and send system data to Elastic Security in real time.', } ); diff --git a/x-pack/plugins/security_solution/common/types/detail_panel/index.ts b/x-pack/plugins/security_solution/common/types/detail_panel/index.ts index ad785acf1d5bf..454c1c5ff3a26 100644 --- a/x-pack/plugins/security_solution/common/types/detail_panel/index.ts +++ b/x-pack/plugins/security_solution/common/types/detail_panel/index.ts @@ -5,7 +5,6 @@ * 2.0. */ -import type { FlowTargetSourceDest } from '../../search_strategy'; import type { TimelineTabs } from '../timeline'; type EmptyObject = Record; @@ -21,26 +20,7 @@ export type ExpandedEventType = } | EmptyObject; -export type ExpandedHostType = - | { - panelView?: 'hostDetail'; - params?: { - hostName: string; - }; - } - | EmptyObject; - -export type ExpandedNetworkType = - | { - panelView?: 'networkDetail'; - params?: { - ip: string; - flowTarget: FlowTargetSourceDest; - }; - } - | EmptyObject; - -export type ExpandedDetailType = ExpandedEventType | ExpandedHostType | ExpandedNetworkType; +export type ExpandedDetailType = ExpandedEventType; export type ExpandedDetailTimeline = { [tab in TimelineTabs]?: ExpandedDetailType; diff --git a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml index ca8bae8f42f0f..9a6ff48ba394e 100644 --- a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_detections_api_2023_10_31.bundled.schema.yaml @@ -14,9 +14,177 @@ servers: port: default: '5601' paths: + /api/detection_engine/index: + delete: + operationId: DeleteAlertsIndex + responses: + '200': + content: + application/json: + schema: + type: object + properties: + acknowledged: + type: boolean + required: + - acknowledged + description: Successful response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Not enough permissions response + '404': + content: + application/json: + schema: + type: string + description: Index does not exist response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Delete an alerts index + tags: + - Alert index API + get: + operationId: GetAlertsIndex + responses: + '200': + content: + application/json: + schema: + type: object + properties: + index_mapping_outdated: + nullable: true + type: boolean + name: + type: string + required: + - name + - index_mapping_outdated + description: Successful response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Not enough permissions response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Gets the alert index name if it exists + tags: + - Alert index API + post: + operationId: CreateAlertsIndex + responses: + '200': + content: + application/json: + schema: + type: object + properties: + acknowledged: + type: boolean + required: + - acknowledged + description: Successful response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Not enough permissions response + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Create an alerts index + tags: + - Alert index API + /api/detection_engine/privileges: + get: + description: > + Retrieves whether or not the user is authenticated, and the user's + Kibana + + space and index privileges, which determine if the user can create an + + index for the Elastic Security alerts generated by + + detection engine rules. + operationId: GetPrivileges + responses: + '200': + content: + application/json: + schema: + type: object + properties: + has_encryption_key: + type: boolean + is_authenticated: + type: boolean + required: + - is_authenticated + - has_encryption_key + description: Successful response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Returns user privileges for the Kibana space + tags: + - Privileges API /api/detection_engine/rules: delete: - description: Deletes a single rule using the `rule_id` or `id` field. + description: Delete a detection rule using the `rule_id` or `id` field. operationId: DeleteRule parameters: - description: The rule's `id` value. @@ -38,10 +206,11 @@ paths: schema: $ref: '#/components/schemas/RuleResponse' description: Indicates a successful call. + summary: Delete a detection rule tags: - Rules API get: - description: Read a single rule + description: Retrieve a detection rule using the `rule_id` or `id` field. operationId: ReadRule parameters: - description: The rule's `id` value. @@ -63,10 +232,13 @@ paths: schema: $ref: '#/components/schemas/RuleResponse' description: Indicates a successful call. + summary: Retrieve a detection rule tags: - Rules API patch: - description: Patch a single rule + description: >- + Update specific fields of an existing detection rule using the `rule_id` + or `id` field. operationId: PatchRule requestBody: content: @@ -81,10 +253,11 @@ paths: schema: $ref: '#/components/schemas/RuleResponse' description: Indicates a successful call. + summary: Patch a detection rule tags: - Rules API post: - description: Create a single detection rule + description: Create a new detection rule. operationId: CreateRule requestBody: content: @@ -99,10 +272,17 @@ paths: schema: $ref: '#/components/schemas/RuleResponse' description: Indicates a successful call. + summary: Create a detection rule tags: - Rules API put: - description: Update a single rule + description: > + Update a detection rule using the `rule_id` or `id` field. The original + rule is replaced, and all unspecified fields are deleted. + + > info + + > You cannot modify the `id` or `rule_id` values. operationId: UpdateRule requestBody: content: @@ -117,13 +297,15 @@ paths: schema: $ref: '#/components/schemas/RuleResponse' description: Indicates a successful call. + summary: Update a detection rule tags: - Rules API /api/detection_engine/rules/_bulk_action: post: description: >- - The bulk action is applied to all rules that match the filter or to the - list of rules by their IDs. + Apply a bulk action, such as bulk edit, duplicate, or delete, to + multiple detection rules. The bulk action is applied to all rules that + match the query or to the rules listed by their IDs. operationId: PerformBulkAction parameters: - description: Enables dry run mode for the request call. @@ -142,6 +324,7 @@ paths: - $ref: '#/components/schemas/BulkEnableRules' - $ref: '#/components/schemas/BulkExportRules' - $ref: '#/components/schemas/BulkDuplicateRules' + - $ref: '#/components/schemas/BulkManualRuleRun' - $ref: '#/components/schemas/BulkEditRules' responses: '200': @@ -152,13 +335,13 @@ paths: - $ref: '#/components/schemas/BulkEditActionResponse' - $ref: '#/components/schemas/BulkExportActionResponse' description: OK - summary: Applies a bulk action to multiple rules + summary: Apply a bulk action to detection rules tags: - Bulk API /api/detection_engine/rules/_bulk_create: post: deprecated: true - description: Creates new detection rules in bulk. + description: Create new detection rules in bulk. operationId: BulkCreateRules requestBody: content: @@ -176,12 +359,13 @@ paths: schema: $ref: '#/components/schemas/BulkCrudRulesResponse' description: Indicates a successful call. + summary: Create multiple detection rules tags: - Bulk API /api/detection_engine/rules/_bulk_delete: delete: deprecated: true - description: Deletes multiple rules. + description: Delete detection rules in bulk. operationId: BulkDeleteRules requestBody: content: @@ -206,12 +390,84 @@ paths: schema: $ref: '#/components/schemas/BulkCrudRulesResponse' description: Indicates a successful call. + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Delete multiple detection rules + tags: + - Bulk API + post: + deprecated: true + description: Deletes multiple rules. + operationId: BulkDeleteRulesPost + requestBody: + content: + application/json: + schema: + items: + type: object + properties: + id: + $ref: '#/components/schemas/RuleObjectId' + rule_id: + $ref: '#/components/schemas/RuleSignatureId' + type: array + description: >- + A JSON array of `id` or `rule_id` fields of the rules you want to + delete. + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/BulkCrudRulesResponse' + description: Indicates a successful call. + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response tags: - Bulk API /api/detection_engine/rules/_bulk_update: patch: deprecated: true - description: Updates multiple rules using the `PATCH` method. + description: >- + Update specific fields of existing detection rules using the `rule_id` + or `id` field. operationId: BulkPatchRules requestBody: content: @@ -229,11 +485,18 @@ paths: schema: $ref: '#/components/schemas/BulkCrudRulesResponse' description: Indicates a successful call. + summary: Patch multiple detection rules tags: - Bulk API put: deprecated: true - description: Updates multiple rules using the `PUT` method. + description: > + Update multiple detection rules using the `rule_id` or `id` field. The + original rules are replaced, and all unspecified fields are deleted. + + > info + + > You cannot modify the `id` or `rule_id` values. operationId: BulkUpdateRules requestBody: content: @@ -253,14 +516,22 @@ paths: schema: $ref: '#/components/schemas/BulkCrudRulesResponse' description: Indicates a successful call. + summary: Update multiple detection rules tags: - Bulk API /api/detection_engine/rules/_export: post: - description: >- - Exports rules to an `.ndjson` file. The following configuration items - are also included in the `.ndjson` file - Actions, Exception lists. - Prebuilt rules cannot be exported. + description: > + Export detection rules to an `.ndjson` file. The following configuration + items are also included in the `.ndjson` file: + + - Actions + + - Exception lists + + > info + + > You cannot export prebuilt rules. operationId: ExportRules parameters: - description: Determines whether a summary of the exported rules is returned. @@ -308,13 +579,14 @@ paths: format: binary type: string description: Indicates a successful call. - summary: Export rules + summary: Export detection rules tags: - Import/Export API - summary: Exports rules to an `.ndjson` file /api/detection_engine/rules/_find: get: - description: Finds rules that match the given query. + description: >- + Retrieve a paginated list of detection rules. By default, the first page + is returned, with 20 results per page. operationId: FindRules parameters: - in: query @@ -381,13 +653,18 @@ paths: - total - data description: Successful response + summary: List all detection rules tags: - Rules API /api/detection_engine/rules/_import: post: - description: >- - Imports rules from an `.ndjson` file, including actions and exception - lists. + description: > + Import detection rules from an `.ndjson` file, including actions and + exception lists. The request must include: + + - The `Content-Type: multipart/form-data` HTTP header. + + - A link to the `.ndjson` file containing the rules. operationId: ImportRules parameters: - description: >- @@ -490,12 +767,12 @@ paths: - action_connectors_success - action_connectors_success_count description: Indicates a successful call. - summary: Import rules + summary: Import detection rules tags: - Import/Export API - summary: Imports rules from an `.ndjson` file /api/detection_engine/rules/prepackaged: put: + description: Install and update all Elastic prebuilt detection rules and Timelines. operationId: InstallPrebuiltRulesAndTimelines responses: '200': @@ -527,11 +804,14 @@ paths: - timelines_installed - timelines_updated description: Indicates a successful call - summary: Installs all Elastic prebuilt rules and timelines + summary: Install prebuilt detection rules and Timelines tags: - Prebuilt Rules API /api/detection_engine/rules/prepackaged/_status: get: + description: >- + Retrieve the status of all Elastic prebuilt detection rules and + Timelines. operationId: GetPrebuiltRulesAndTimelinesStatus responses: '200': @@ -582,12 +862,94 @@ paths: - timelines_not_installed - timelines_not_updated description: Indicates a successful call - summary: Get the status of Elastic prebuilt rules + summary: Retrieve the status of prebuilt detection rules and Timelines tags: - Prebuilt Rules API + /api/detection_engine/rules/preview: + post: + operationId: RulePreview + requestBody: + content: + application/json: + schema: + anyOf: + - allOf: + - $ref: '#/components/schemas/EqlRuleCreateProps' + - $ref: '#/components/schemas/RulePreviewParams' + - allOf: + - $ref: '#/components/schemas/QueryRuleCreateProps' + - $ref: '#/components/schemas/RulePreviewParams' + - allOf: + - $ref: '#/components/schemas/SavedQueryRuleCreateProps' + - $ref: '#/components/schemas/RulePreviewParams' + - allOf: + - $ref: '#/components/schemas/ThresholdRuleCreateProps' + - $ref: '#/components/schemas/RulePreviewParams' + - allOf: + - $ref: '#/components/schemas/ThreatMatchRuleCreateProps' + - $ref: '#/components/schemas/RulePreviewParams' + - allOf: + - $ref: '#/components/schemas/MachineLearningRuleCreateProps' + - $ref: '#/components/schemas/RulePreviewParams' + - allOf: + - $ref: '#/components/schemas/NewTermsRuleCreateProps' + - $ref: '#/components/schemas/RulePreviewParams' + - allOf: + - $ref: '#/components/schemas/EsqlRuleCreateProps' + - $ref: '#/components/schemas/RulePreviewParams' + discriminator: + propertyName: type + description: >- + An object containing tags to add or remove and alert ids the changes + will be applied + required: true + responses: + '200': + content: + application/json: + schema: + type: object + properties: + isAborted: + type: boolean + logs: + items: + $ref: '#/components/schemas/RulePreviewLogs' + type: array + previewId: + $ref: '#/components/schemas/NonEmptyString' + required: + - logs + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Preview rule alerts generated on specified time range + tags: + - Rule preview API /api/detection_engine/signals/assignees: post: - description: Assigns users to alerts. + description: | + Assign users to detection alerts, and unassign them from alerts. + > info + > You cannot add and remove the same assignee in the same request. operationId: SetAlertAssignees requestBody: content: @@ -610,9 +972,433 @@ paths: description: Indicates a successful call. '400': description: Invalid request. - summary: Assigns users to alerts + summary: Assign and unassign users from detection alerts + /api/detection_engine/signals/finalize_migration: + post: + description: > + Finalize successful migrations of detection alerts. This replaces the + original index's alias with the successfully migrated index's alias. + + The endpoint is idempotent; therefore, it can safely be used to poll a + given migration and, upon completion, + + finalize it. + operationId: FinalizeAlertsMigration + requestBody: + content: + application/json: + schema: + type: object + properties: + migration_ids: + items: + type: string + minItems: 1 + type: array + required: + - migration_ids + description: Array of `migration_id`s to finalize + required: true + responses: + '200': + content: + application/json: + schema: + items: + $ref: '#/components/schemas/MigrationFinalizationResult' + type: array + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Finalize detection alert migrations + tags: + - Alerts migration API + /api/detection_engine/signals/migration: + delete: + description: > + Migrations favor data integrity over shard size. Consequently, unused or + orphaned indices are artifacts of + + the migration process. A successful migration will result in both the + old and new indices being present. + + As such, the old, orphaned index can (and likely should) be deleted. + + + While you can delete these indices manually, + + the endpoint accomplishes this task by applying a deletion policy to the + relevant index, causing it to be deleted + + after 30 days. It also deletes other artifacts specific to the migration + implementation. + operationId: AlertsMigrationCleanup + requestBody: + content: + application/json: + schema: + type: object + properties: + migration_ids: + items: + type: string + minItems: 1 + type: array + required: + - migration_ids + description: Array of `migration_id`s to cleanup + required: true + responses: + '200': + content: + application/json: + schema: + items: + $ref: '#/components/schemas/MigrationCleanupResult' + type: array + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Clean up detection alert migrations + tags: + - Alerts migration API + post: + description: > + Initiate a migration of detection alerts. + + Migrations are initiated per index. While the process is neither + destructive nor interferes with existing data, it may be + resource-intensive. As such, it is recommended that you plan your + migrations accordingly. + operationId: CreateAlertsMigration + requestBody: + content: + application/json: + schema: + allOf: + - type: object + properties: + index: + items: + $ref: '#/components/schemas/NonEmptyString' + minItems: 1 + type: array + required: + - index + - $ref: '#/components/schemas/AlertsReindexOptions' + description: Alerts migration parameters + required: true + responses: + '200': + content: + application/json: + schema: + type: object + properties: + indices: + items: + oneOf: + - $ref: '#/components/schemas/AlertsIndexMigrationSuccess' + - $ref: '#/components/schemas/AlertsIndexMigrationError' + - $ref: '#/components/schemas/SkippedAlertsIndexMigration' + type: array + required: + - indices + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Initiate a detection alert migration + tags: + - Alerts migration API + /api/detection_engine/signals/migration_status: + post: + description: >- + Retrieve indices that contain detection alerts of a particular age, + along with migration information for each of those indices. + operationId: GetAlertsMigrationStatus + parameters: + - description: Maximum age of qualifying detection alerts + in: query + name: from + required: true + schema: + description: > + Time from which data is analyzed. For example, now-4200s means the + rule analyzes data from 70 minutes + + before its start time. Defaults to now-6m (analyzes data from 6 + minutes before the start time). + format: date-math + type: string + responses: + '200': + content: + application/json: + schema: + type: object + properties: + indices: + items: + $ref: '#/components/schemas/IndexMigrationStatus' + type: array + required: + - indices + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Retrieve the status of detection alert migrations + tags: + - Alerts migration API + /api/detection_engine/signals/search: + post: + description: Find and/or aggregate detection alerts that match the given query. + operationId: SearchAlerts + requestBody: + content: + application/json: + schema: + description: Elasticsearch query and aggregation request + type: object + properties: + _source: + oneOf: + - type: boolean + - type: string + - items: + type: string + type: array + aggs: + additionalProperties: true + type: object + fields: + items: + type: string + type: array + query: + additionalProperties: true + type: object + runtime_mappings: + additionalProperties: true + type: object + size: + minimum: 0 + type: integer + sort: + $ref: '#/components/schemas/AlertsSort' + track_total_hits: + type: boolean + description: Search and/or aggregation query + required: true + responses: + '200': + content: + application/json: + schema: + additionalProperties: true + description: Elasticsearch search response + type: object + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Find and/or aggregate detection alerts + tags: + - Alerts API + /api/detection_engine/signals/status: + post: + description: Set the status of one or more detection alerts. + operationId: SetAlertsStatus + requestBody: + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/SetAlertsStatusByIds' + - $ref: '#/components/schemas/SetAlertsStatusByQuery' + description: >- + An object containing desired status and explicit alert ids or a query + to select alerts + required: true + responses: + '200': + content: + application/json: + schema: + additionalProperties: true + description: Elasticsearch update by query response + type: object + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Set a detection alert status + tags: + - Alerts API + /api/detection_engine/signals/tags: + post: + description: | + And tags to detection alerts, and remove them from alerts. + > info + > You cannot add and remove the same alert tag in the same request. + operationId: ManageAlertTags + requestBody: + content: + application/json: + schema: + type: object + properties: + ids: + $ref: '#/components/schemas/AlertIds' + tags: + $ref: '#/components/schemas/ManageAlertTags' + required: + - ids + - tags + description: >- + An object containing tags to add or remove and alert ids the changes + will be applied + required: true + responses: + '200': + content: + application/json: + schema: + additionalProperties: true + description: Elasticsearch update by query response + type: object + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Add and remove detection alert tags + tags: + - Alerts API /api/detection_engine/tags: get: + description: List all unique tags from all detection rules. operationId: ReadTags responses: '200': @@ -621,10 +1407,9 @@ paths: schema: $ref: '#/components/schemas/RuleTagArray' description: Indicates a successful call - summary: Aggregates and returns all unique tags from all rules + summary: List all detection rule tags tags: - Tags API - summary: Aggregates and returns rule tags components: schemas: AlertAssignees: @@ -653,9 +1438,70 @@ components: deprecated: true description: (deprecated) Has no effect. type: string + AlertsIndexMigrationError: + type: object + properties: + error: + type: object + properties: + message: + type: string + status_code: + type: string + required: + - message + - status_code + index: + type: string + required: + - index + - error + AlertsIndexMigrationSuccess: + type: object + properties: + index: + type: string + migration_id: + type: string + migration_index: + type: string + required: + - index + - migration_id + - migration_index AlertsIndexNamespace: description: Has no effect. type: string + AlertsReindexOptions: + type: object + properties: + requests_per_second: + minimum: 1 + type: integer + size: + minimum: 1 + type: integer + slices: + minimum: 1 + type: integer + AlertsSort: + oneOf: + - $ref: '#/components/schemas/AlertsSortCombinations' + - items: + $ref: '#/components/schemas/AlertsSortCombinations' + type: array + AlertsSortCombinations: + anyOf: + - type: string + - additionalProperties: true + type: object + AlertStatus: + enum: + - open + - closed + - acknowledged + - in-progress + type: string AlertSuppression: type: object properties: @@ -700,6 +1546,22 @@ components: - doNotSuppress - suppress type: string + AlertTag: + $ref: '#/components/schemas/NonEmptyString' + AlertTags: + items: + $ref: '#/components/schemas/AlertTag' + type: array + AlertVersion: + type: object + properties: + count: + type: integer + version: + type: integer + required: + - version + - count AnomalyThreshold: description: Anomaly threshold minimum: 0 @@ -782,7 +1644,9 @@ components: type: object properties: interval: - description: Interval in which the rule is executed + description: >- + Interval in which the rule runs. For example, `"1h"` means the + rule runs every hour. example: 1h pattern: '^[1-9]\d*[smh]$' type: string @@ -838,6 +1702,8 @@ components: - MACHINE_LEARNING_INDEX_PATTERN - ESQL_INDEX_PATTERN - INVESTIGATION_FIELDS_FEATURE + - MANUAL_RULE_RUN_FEATURE + - MANUAL_RULE_RUN_DISABLED_RULE type: string BulkActionSkipResult: type: object @@ -1057,6 +1923,36 @@ components: type: string required: - action + BulkManualRuleRun: + type: object + properties: + action: + enum: + - run + type: string + ids: + description: Array of rule IDs + items: + type: string + minItems: 1 + type: array + query: + description: Query to filter rules + type: string + run: + type: object + properties: + end_date: + description: End date of the manual rule run + type: string + start_date: + description: Start date of the manual rule run + type: string + required: + - start_date + required: + - action + - run ConcurrentSearches: minimum: 1 type: integer @@ -2065,6 +2961,29 @@ components: type: string HistoryWindowStart: $ref: '#/components/schemas/NonEmptyString' + IndexMigrationStatus: + type: object + properties: + index: + $ref: '#/components/schemas/NonEmptyString' + is_outdated: + type: boolean + migrations: + items: + $ref: '#/components/schemas/MigrationStatus' + type: array + signal_versions: + items: + $ref: '#/components/schemas/AlertVersion' + type: array + version: + type: integer + required: + - index + - version + - signal_versions + - migrations + - is_outdated IndexPatternArray: items: type: string @@ -2082,6 +3001,34 @@ components: required: - type InvestigationFields: + description: > + Schema for fields relating to investigation fields. These are user + defined fields we use to highlight + + in various features in the UI such as alert details flyout and + exceptions auto-population from alert. + + Added in PR #163235 + + Right now we only have a single field but anticipate adding more related + fields to store various + + configuration states such as `override` - where a user might say if they + want only these fields to + + display, or if they want these fields + the fields we select. When + expanding this field, it may look + + something like: + + ```typescript + + const investigationFields = z.object({ + field_names: NonEmptyArray(NonEmptyString), + override: z.boolean().optional(), + }); + + ``` type: object properties: field_names: @@ -2237,7 +3184,9 @@ components: - $ref: '#/components/schemas/ResponseFields' - $ref: '#/components/schemas/MachineLearningRuleResponseFields' MachineLearningRuleCreateFields: - $ref: '#/components/schemas/MachineLearningRuleRequiredFields' + allOf: + - $ref: '#/components/schemas/MachineLearningRuleRequiredFields' + - $ref: '#/components/schemas/MachineLearningRuleOptionalFields' MachineLearningRuleCreateProps: allOf: - type: object @@ -2332,18 +3281,25 @@ components: - risk_score - severity - $ref: '#/components/schemas/MachineLearningRuleCreateFields' - MachineLearningRulePatchFields: + MachineLearningRuleOptionalFields: type: object properties: - anomaly_threshold: - $ref: '#/components/schemas/AnomalyThreshold' - machine_learning_job_id: - $ref: '#/components/schemas/MachineLearningJobId' - type: - description: Rule type - enum: - - machine_learning - type: string + alert_suppression: + $ref: '#/components/schemas/AlertSuppression' + MachineLearningRulePatchFields: + allOf: + - type: object + properties: + anomaly_threshold: + $ref: '#/components/schemas/AnomalyThreshold' + machine_learning_job_id: + $ref: '#/components/schemas/MachineLearningJobId' + type: + description: Rule type + enum: + - machine_learning + type: string + - $ref: '#/components/schemas/MachineLearningRuleOptionalFields' MachineLearningRulePatchProps: allOf: - type: object @@ -2452,7 +3408,9 @@ components: - machine_learning_job_id - anomaly_threshold MachineLearningRuleResponseFields: - $ref: '#/components/schemas/MachineLearningRuleRequiredFields' + allOf: + - $ref: '#/components/schemas/MachineLearningRuleRequiredFields' + - $ref: '#/components/schemas/MachineLearningRuleOptionalFields' MachineLearningRuleUpdateProps: allOf: - type: object @@ -2549,9 +3507,117 @@ components: - risk_score - severity - $ref: '#/components/schemas/MachineLearningRuleCreateFields' + ManageAlertTags: + type: object + properties: + tags_to_add: + $ref: '#/components/schemas/AlertTags' + tags_to_remove: + $ref: '#/components/schemas/AlertTags' + required: + - tags_to_add + - tags_to_remove MaxSignals: minimum: 1 type: integer + MigrationCleanupResult: + type: object + properties: + destinationIndex: + type: string + error: + type: object + properties: + message: + type: string + status_code: + type: integer + required: + - message + - status_code + id: + type: string + sourceIndex: + type: string + status: + enum: + - success + - failure + - pending + type: string + updated: + format: date-time + type: string + version: + type: string + required: + - id + - destinationIndex + - status + - sourceIndex + - version + - updated + MigrationFinalizationResult: + type: object + properties: + completed: + type: boolean + destinationIndex: + type: string + error: + type: object + properties: + message: + type: string + status_code: + type: integer + required: + - message + - status_code + id: + type: string + sourceIndex: + type: string + status: + enum: + - success + - failure + - pending + type: string + updated: + format: date-time + type: string + version: + type: string + required: + - id + - completed + - destinationIndex + - status + - sourceIndex + - version + - updated + MigrationStatus: + type: object + properties: + id: + $ref: '#/components/schemas/NonEmptyString' + status: + enum: + - success + - failure + - pending + type: string + updated: + format: date-time + type: string + version: + type: integer + required: + - id + - status + - version + - updated NewTermsFields: items: type: string @@ -3085,7 +4151,7 @@ components: platform: type: string query: - description: Query to execute + description: Query to run type: string removed: type: boolean @@ -3109,6 +4175,19 @@ components: required: - action_type_id - params + PlatformErrorResponse: + type: object + properties: + error: + type: string + message: + type: string + statusCode: + type: integer + required: + - statusCode + - error + - message ProcessesParams: type: object properties: @@ -3590,6 +4669,63 @@ components: - severity - $ref: '#/components/schemas/QueryRuleCreateFields' RelatedIntegration: + description: > + Related integration is a potential dependency of a rule. It's assumed + that if the user installs + + one of the related integrations of a rule, the rule might start to work + properly because it will + + have source events (generated by this integration) potentially matching + the rule's query. + + + NOTE: Proper work is not guaranteed, because a related integration, if + installed, can be + + configured differently or generate data that is not necessarily relevant + for this rule. + + + Related integration is a combination of a Fleet package and (optionally) + one of the + + package's "integrations" that this package contains. It is represented + by 3 properties: + + + - `package`: name of the package (required, unique id) + + - `version`: version of the package (required, semver-compatible) + + - `integration`: name of the integration of this package (optional, id + within the package) + + + There are Fleet packages like `windows` that contain only one + integration; in this case, + + `integration` should be unspecified. There are also packages like `aws` + and `azure` that contain + + several integrations; in this case, `integration` should be specified. + + + @example + + const x: RelatedIntegration = { + package: 'windows', + version: '1.5.x', + }; + + + @example + + const x: RelatedIntegration = { + package: 'azure', + version: '~1.1.6', + integration: 'activitylogs', + }; type: object properties: integration: @@ -3606,7 +4742,40 @@ components: $ref: '#/components/schemas/RelatedIntegration' type: array RequiredField: - description: Describes an Elasticsearch field that is needed for the rule to function + description: > + Describes an Elasticsearch field that is needed for the rule to + function. + + + Almost all types of Security rules check source event documents for a + match to some kind of + + query or filter. If a document has certain field with certain values, + then it's a match and + + the rule will generate an alert. + + + Required field is an event field that must be present in the source + indices of a given rule. + + + @example + + const standardEcsField: RequiredField = { + name: 'event.action', + type: 'keyword', + ecs: true, + }; + + + @example + + const nonEcsField: RequiredField = { + name: 'winlog.event_data.AttributeLDAPDisplayName', + type: 'keyword', + ecs: false, + }; type: object properties: ecs: @@ -3782,7 +4951,7 @@ components: to the connector type. type: object RuleActionThrottle: - description: Defines the interval on which a rule's actions are executed. + description: Defines how often rule actions are taken. oneOf: - enum: - no_actions @@ -3944,10 +5113,10 @@ components: type: string RuleIntervalFrom: description: >- - Time from which data is analyzed each time the rule executes, using a - date math range. For example, now-4200s means the rule analyzes data - from 70 minutes before its start time. Defaults to now-6m (analyzes data - from 6 minutes before the start time). + Time from which data is analyzed each time the rule runs, using a date + math range. For example, now-4200s means the rule analyzes data from 70 + minutes before its start time. Defaults to now-6m (analyzes data from 6 + minutes before the start time). format: date-math type: string RuleIntervalTo: @@ -3976,6 +5145,37 @@ components: - $ref: '#/components/schemas/MachineLearningRulePatchProps' - $ref: '#/components/schemas/NewTermsRulePatchProps' - $ref: '#/components/schemas/EsqlRulePatchProps' + RulePreviewLogs: + type: object + properties: + duration: + description: Execution duration in milliseconds + type: integer + errors: + items: + $ref: '#/components/schemas/NonEmptyString' + type: array + startedAt: + $ref: '#/components/schemas/NonEmptyString' + warnings: + items: + $ref: '#/components/schemas/NonEmptyString' + type: array + required: + - errors + - warnings + - duration + RulePreviewParams: + type: object + properties: + invocationCount: + type: integer + timeframeEnd: + format: date-time + type: string + required: + - invocationCount + - timeframeEnd RuleQuery: type: string RuleReferenceArray: @@ -4500,6 +5700,36 @@ components: - risk_score - severity - $ref: '#/components/schemas/SavedQueryRuleCreateFields' + SetAlertsStatusByIds: + type: object + properties: + signal_ids: + items: + $ref: '#/components/schemas/NonEmptyString' + minItems: 1 + type: array + status: + $ref: '#/components/schemas/AlertStatus' + required: + - signal_ids + - status + SetAlertsStatusByQuery: + type: object + properties: + conflicts: + default: abort + enum: + - abort + - proceed + type: string + query: + additionalProperties: true + type: object + status: + $ref: '#/components/schemas/AlertStatus' + required: + - query + - status SetupGuide: type: string Severity: @@ -4531,6 +5761,23 @@ components: - severity - value type: array + SiemErrorResponse: + type: object + properties: + message: + type: string + status_code: + type: integer + required: + - status_code + - message + SkippedAlertsIndexMigration: + type: object + properties: + index: + type: string + required: + - index SortOrder: enum: - asc @@ -5073,7 +6320,7 @@ components: - severity - $ref: '#/components/schemas/ThreatMatchRuleCreateFields' ThreatQuery: - description: Query to execute + description: Query to run type: string ThreatSubtechnique: type: object @@ -5680,3 +6927,4 @@ components: type: http security: - BasicAuth: [] +tags: ! '' diff --git a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml index 94682a8e1b8f9..b19ec98384303 100644 --- a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_detections_api_2023_10_31.bundled.schema.yaml @@ -14,9 +14,51 @@ servers: port: default: '5601' paths: + /api/detection_engine/privileges: + get: + description: > + Retrieves whether or not the user is authenticated, and the user's + Kibana + + space and index privileges, which determine if the user can create an + + index for the Elastic Security alerts generated by + + detection engine rules. + operationId: GetPrivileges + responses: + '200': + content: + application/json: + schema: + type: object + properties: + has_encryption_key: + type: boolean + is_authenticated: + type: boolean + required: + - is_authenticated + - has_encryption_key + description: Successful response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Returns user privileges for the Kibana space + tags: + - Privileges API /api/detection_engine/rules: delete: - description: Deletes a single rule using the `rule_id` or `id` field. + description: Delete a detection rule using the `rule_id` or `id` field. operationId: DeleteRule parameters: - description: The rule's `id` value. @@ -38,10 +80,11 @@ paths: schema: $ref: '#/components/schemas/RuleResponse' description: Indicates a successful call. + summary: Delete a detection rule tags: - Rules API get: - description: Read a single rule + description: Retrieve a detection rule using the `rule_id` or `id` field. operationId: ReadRule parameters: - description: The rule's `id` value. @@ -63,10 +106,13 @@ paths: schema: $ref: '#/components/schemas/RuleResponse' description: Indicates a successful call. + summary: Retrieve a detection rule tags: - Rules API patch: - description: Patch a single rule + description: >- + Update specific fields of an existing detection rule using the `rule_id` + or `id` field. operationId: PatchRule requestBody: content: @@ -81,10 +127,11 @@ paths: schema: $ref: '#/components/schemas/RuleResponse' description: Indicates a successful call. + summary: Patch a detection rule tags: - Rules API post: - description: Create a single detection rule + description: Create a new detection rule. operationId: CreateRule requestBody: content: @@ -99,10 +146,17 @@ paths: schema: $ref: '#/components/schemas/RuleResponse' description: Indicates a successful call. + summary: Create a detection rule tags: - Rules API put: - description: Update a single rule + description: > + Update a detection rule using the `rule_id` or `id` field. The original + rule is replaced, and all unspecified fields are deleted. + + > info + + > You cannot modify the `id` or `rule_id` values. operationId: UpdateRule requestBody: content: @@ -117,13 +171,15 @@ paths: schema: $ref: '#/components/schemas/RuleResponse' description: Indicates a successful call. + summary: Update a detection rule tags: - Rules API /api/detection_engine/rules/_bulk_action: post: description: >- - The bulk action is applied to all rules that match the filter or to the - list of rules by their IDs. + Apply a bulk action, such as bulk edit, duplicate, or delete, to + multiple detection rules. The bulk action is applied to all rules that + match the query or to the rules listed by their IDs. operationId: PerformBulkAction parameters: - description: Enables dry run mode for the request call. @@ -142,6 +198,7 @@ paths: - $ref: '#/components/schemas/BulkEnableRules' - $ref: '#/components/schemas/BulkExportRules' - $ref: '#/components/schemas/BulkDuplicateRules' + - $ref: '#/components/schemas/BulkManualRuleRun' - $ref: '#/components/schemas/BulkEditRules' responses: '200': @@ -152,15 +209,22 @@ paths: - $ref: '#/components/schemas/BulkEditActionResponse' - $ref: '#/components/schemas/BulkExportActionResponse' description: OK - summary: Applies a bulk action to multiple rules + summary: Apply a bulk action to detection rules tags: - Bulk API /api/detection_engine/rules/_export: post: - description: >- - Exports rules to an `.ndjson` file. The following configuration items - are also included in the `.ndjson` file - Actions, Exception lists. - Prebuilt rules cannot be exported. + description: > + Export detection rules to an `.ndjson` file. The following configuration + items are also included in the `.ndjson` file: + + - Actions + + - Exception lists + + > info + + > You cannot export prebuilt rules. operationId: ExportRules parameters: - description: Determines whether a summary of the exported rules is returned. @@ -208,13 +272,14 @@ paths: format: binary type: string description: Indicates a successful call. - summary: Export rules + summary: Export detection rules tags: - Import/Export API - summary: Exports rules to an `.ndjson` file /api/detection_engine/rules/_find: get: - description: Finds rules that match the given query. + description: >- + Retrieve a paginated list of detection rules. By default, the first page + is returned, with 20 results per page. operationId: FindRules parameters: - in: query @@ -281,13 +346,18 @@ paths: - total - data description: Successful response + summary: List all detection rules tags: - Rules API /api/detection_engine/rules/_import: post: - description: >- - Imports rules from an `.ndjson` file, including actions and exception - lists. + description: > + Import detection rules from an `.ndjson` file, including actions and + exception lists. The request must include: + + - The `Content-Type: multipart/form-data` HTTP header. + + - A link to the `.ndjson` file containing the rules. operationId: ImportRules parameters: - description: >- @@ -390,13 +460,94 @@ paths: - action_connectors_success - action_connectors_success_count description: Indicates a successful call. - summary: Import rules + summary: Import detection rules tags: - Import/Export API - summary: Imports rules from an `.ndjson` file + /api/detection_engine/rules/preview: + post: + operationId: RulePreview + requestBody: + content: + application/json: + schema: + anyOf: + - allOf: + - $ref: '#/components/schemas/EqlRuleCreateProps' + - $ref: '#/components/schemas/RulePreviewParams' + - allOf: + - $ref: '#/components/schemas/QueryRuleCreateProps' + - $ref: '#/components/schemas/RulePreviewParams' + - allOf: + - $ref: '#/components/schemas/SavedQueryRuleCreateProps' + - $ref: '#/components/schemas/RulePreviewParams' + - allOf: + - $ref: '#/components/schemas/ThresholdRuleCreateProps' + - $ref: '#/components/schemas/RulePreviewParams' + - allOf: + - $ref: '#/components/schemas/ThreatMatchRuleCreateProps' + - $ref: '#/components/schemas/RulePreviewParams' + - allOf: + - $ref: '#/components/schemas/MachineLearningRuleCreateProps' + - $ref: '#/components/schemas/RulePreviewParams' + - allOf: + - $ref: '#/components/schemas/NewTermsRuleCreateProps' + - $ref: '#/components/schemas/RulePreviewParams' + - allOf: + - $ref: '#/components/schemas/EsqlRuleCreateProps' + - $ref: '#/components/schemas/RulePreviewParams' + discriminator: + propertyName: type + description: >- + An object containing tags to add or remove and alert ids the changes + will be applied + required: true + responses: + '200': + content: + application/json: + schema: + type: object + properties: + isAborted: + type: boolean + logs: + items: + $ref: '#/components/schemas/RulePreviewLogs' + type: array + previewId: + $ref: '#/components/schemas/NonEmptyString' + required: + - logs + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Preview rule alerts generated on specified time range + tags: + - Rule preview API /api/detection_engine/signals/assignees: post: - description: Assigns users to alerts. + description: | + Assign users to detection alerts, and unassign them from alerts. + > info + > You cannot add and remove the same assignee in the same request. operationId: SetAlertAssignees requestBody: content: @@ -419,9 +570,185 @@ paths: description: Indicates a successful call. '400': description: Invalid request. - summary: Assigns users to alerts + summary: Assign and unassign users from detection alerts + /api/detection_engine/signals/search: + post: + description: Find and/or aggregate detection alerts that match the given query. + operationId: SearchAlerts + requestBody: + content: + application/json: + schema: + description: Elasticsearch query and aggregation request + type: object + properties: + _source: + oneOf: + - type: boolean + - type: string + - items: + type: string + type: array + aggs: + additionalProperties: true + type: object + fields: + items: + type: string + type: array + query: + additionalProperties: true + type: object + runtime_mappings: + additionalProperties: true + type: object + size: + minimum: 0 + type: integer + sort: + $ref: '#/components/schemas/AlertsSort' + track_total_hits: + type: boolean + description: Search and/or aggregation query + required: true + responses: + '200': + content: + application/json: + schema: + additionalProperties: true + description: Elasticsearch search response + type: object + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Find and/or aggregate detection alerts + tags: + - Alerts API + /api/detection_engine/signals/status: + post: + description: Set the status of one or more detection alerts. + operationId: SetAlertsStatus + requestBody: + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/SetAlertsStatusByIds' + - $ref: '#/components/schemas/SetAlertsStatusByQuery' + description: >- + An object containing desired status and explicit alert ids or a query + to select alerts + required: true + responses: + '200': + content: + application/json: + schema: + additionalProperties: true + description: Elasticsearch update by query response + type: object + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Set a detection alert status + tags: + - Alerts API + /api/detection_engine/signals/tags: + post: + description: | + And tags to detection alerts, and remove them from alerts. + > info + > You cannot add and remove the same alert tag in the same request. + operationId: ManageAlertTags + requestBody: + content: + application/json: + schema: + type: object + properties: + ids: + $ref: '#/components/schemas/AlertIds' + tags: + $ref: '#/components/schemas/ManageAlertTags' + required: + - ids + - tags + description: >- + An object containing tags to add or remove and alert ids the changes + will be applied + required: true + responses: + '200': + content: + application/json: + schema: + additionalProperties: true + description: Elasticsearch update by query response + type: object + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data response + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication response + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error response + summary: Add and remove detection alert tags + tags: + - Alerts API /api/detection_engine/tags: get: + description: List all unique tags from all detection rules. operationId: ReadTags responses: '200': @@ -430,10 +757,9 @@ paths: schema: $ref: '#/components/schemas/RuleTagArray' description: Indicates a successful call - summary: Aggregates and returns all unique tags from all rules + summary: List all detection rule tags tags: - Tags API - summary: Aggregates and returns rule tags components: schemas: AlertAssignees: @@ -465,6 +791,24 @@ components: AlertsIndexNamespace: description: Has no effect. type: string + AlertsSort: + oneOf: + - $ref: '#/components/schemas/AlertsSortCombinations' + - items: + $ref: '#/components/schemas/AlertsSortCombinations' + type: array + AlertsSortCombinations: + anyOf: + - type: string + - additionalProperties: true + type: object + AlertStatus: + enum: + - open + - closed + - acknowledged + - in-progress + type: string AlertSuppression: type: object properties: @@ -509,6 +853,12 @@ components: - doNotSuppress - suppress type: string + AlertTag: + $ref: '#/components/schemas/NonEmptyString' + AlertTags: + items: + $ref: '#/components/schemas/AlertTag' + type: array AnomalyThreshold: description: Anomaly threshold minimum: 0 @@ -591,7 +941,9 @@ components: type: object properties: interval: - description: Interval in which the rule is executed + description: >- + Interval in which the rule runs. For example, `"1h"` means the + rule runs every hour. example: 1h pattern: '^[1-9]\d*[smh]$' type: string @@ -647,6 +999,8 @@ components: - MACHINE_LEARNING_INDEX_PATTERN - ESQL_INDEX_PATTERN - INVESTIGATION_FIELDS_FEATURE + - MANUAL_RULE_RUN_FEATURE + - MANUAL_RULE_RUN_DISABLED_RULE type: string BulkActionSkipResult: type: object @@ -860,6 +1214,36 @@ components: type: string required: - action + BulkManualRuleRun: + type: object + properties: + action: + enum: + - run + type: string + ids: + description: Array of rule IDs + items: + type: string + minItems: 1 + type: array + query: + description: Query to filter rules + type: string + run: + type: object + properties: + end_date: + description: End date of the manual rule run + type: string + start_date: + description: Start date of the manual rule run + type: string + required: + - start_date + required: + - action + - run ConcurrentSearches: minimum: 1 type: integer @@ -1885,6 +2269,34 @@ components: required: - type InvestigationFields: + description: > + Schema for fields relating to investigation fields. These are user + defined fields we use to highlight + + in various features in the UI such as alert details flyout and + exceptions auto-population from alert. + + Added in PR #163235 + + Right now we only have a single field but anticipate adding more related + fields to store various + + configuration states such as `override` - where a user might say if they + want only these fields to + + display, or if they want these fields + the fields we select. When + expanding this field, it may look + + something like: + + ```typescript + + const investigationFields = z.object({ + field_names: NonEmptyArray(NonEmptyString), + override: z.boolean().optional(), + }); + + ``` type: object properties: field_names: @@ -2040,7 +2452,9 @@ components: - $ref: '#/components/schemas/ResponseFields' - $ref: '#/components/schemas/MachineLearningRuleResponseFields' MachineLearningRuleCreateFields: - $ref: '#/components/schemas/MachineLearningRuleRequiredFields' + allOf: + - $ref: '#/components/schemas/MachineLearningRuleRequiredFields' + - $ref: '#/components/schemas/MachineLearningRuleOptionalFields' MachineLearningRuleCreateProps: allOf: - type: object @@ -2135,18 +2549,25 @@ components: - risk_score - severity - $ref: '#/components/schemas/MachineLearningRuleCreateFields' - MachineLearningRulePatchFields: + MachineLearningRuleOptionalFields: type: object properties: - anomaly_threshold: - $ref: '#/components/schemas/AnomalyThreshold' - machine_learning_job_id: - $ref: '#/components/schemas/MachineLearningJobId' - type: - description: Rule type - enum: - - machine_learning - type: string + alert_suppression: + $ref: '#/components/schemas/AlertSuppression' + MachineLearningRulePatchFields: + allOf: + - type: object + properties: + anomaly_threshold: + $ref: '#/components/schemas/AnomalyThreshold' + machine_learning_job_id: + $ref: '#/components/schemas/MachineLearningJobId' + type: + description: Rule type + enum: + - machine_learning + type: string + - $ref: '#/components/schemas/MachineLearningRuleOptionalFields' MachineLearningRulePatchProps: allOf: - type: object @@ -2255,7 +2676,9 @@ components: - machine_learning_job_id - anomaly_threshold MachineLearningRuleResponseFields: - $ref: '#/components/schemas/MachineLearningRuleRequiredFields' + allOf: + - $ref: '#/components/schemas/MachineLearningRuleRequiredFields' + - $ref: '#/components/schemas/MachineLearningRuleOptionalFields' MachineLearningRuleUpdateProps: allOf: - type: object @@ -2352,6 +2775,16 @@ components: - risk_score - severity - $ref: '#/components/schemas/MachineLearningRuleCreateFields' + ManageAlertTags: + type: object + properties: + tags_to_add: + $ref: '#/components/schemas/AlertTags' + tags_to_remove: + $ref: '#/components/schemas/AlertTags' + required: + - tags_to_add + - tags_to_remove MaxSignals: minimum: 1 type: integer @@ -2888,7 +3321,7 @@ components: platform: type: string query: - description: Query to execute + description: Query to run type: string removed: type: boolean @@ -2912,6 +3345,19 @@ components: required: - action_type_id - params + PlatformErrorResponse: + type: object + properties: + error: + type: string + message: + type: string + statusCode: + type: integer + required: + - statusCode + - error + - message ProcessesParams: type: object properties: @@ -3393,6 +3839,63 @@ components: - severity - $ref: '#/components/schemas/QueryRuleCreateFields' RelatedIntegration: + description: > + Related integration is a potential dependency of a rule. It's assumed + that if the user installs + + one of the related integrations of a rule, the rule might start to work + properly because it will + + have source events (generated by this integration) potentially matching + the rule's query. + + + NOTE: Proper work is not guaranteed, because a related integration, if + installed, can be + + configured differently or generate data that is not necessarily relevant + for this rule. + + + Related integration is a combination of a Fleet package and (optionally) + one of the + + package's "integrations" that this package contains. It is represented + by 3 properties: + + + - `package`: name of the package (required, unique id) + + - `version`: version of the package (required, semver-compatible) + + - `integration`: name of the integration of this package (optional, id + within the package) + + + There are Fleet packages like `windows` that contain only one + integration; in this case, + + `integration` should be unspecified. There are also packages like `aws` + and `azure` that contain + + several integrations; in this case, `integration` should be specified. + + + @example + + const x: RelatedIntegration = { + package: 'windows', + version: '1.5.x', + }; + + + @example + + const x: RelatedIntegration = { + package: 'azure', + version: '~1.1.6', + integration: 'activitylogs', + }; type: object properties: integration: @@ -3409,7 +3912,40 @@ components: $ref: '#/components/schemas/RelatedIntegration' type: array RequiredField: - description: Describes an Elasticsearch field that is needed for the rule to function + description: > + Describes an Elasticsearch field that is needed for the rule to + function. + + + Almost all types of Security rules check source event documents for a + match to some kind of + + query or filter. If a document has certain field with certain values, + then it's a match and + + the rule will generate an alert. + + + Required field is an event field that must be present in the source + indices of a given rule. + + + @example + + const standardEcsField: RequiredField = { + name: 'event.action', + type: 'keyword', + ecs: true, + }; + + + @example + + const nonEcsField: RequiredField = { + name: 'winlog.event_data.AttributeLDAPDisplayName', + type: 'keyword', + ecs: false, + }; type: object properties: ecs: @@ -3585,7 +4121,7 @@ components: to the connector type. type: object RuleActionThrottle: - description: Defines the interval on which a rule's actions are executed. + description: Defines how often rule actions are taken. oneOf: - enum: - no_actions @@ -3747,10 +4283,10 @@ components: type: string RuleIntervalFrom: description: >- - Time from which data is analyzed each time the rule executes, using a - date math range. For example, now-4200s means the rule analyzes data - from 70 minutes before its start time. Defaults to now-6m (analyzes data - from 6 minutes before the start time). + Time from which data is analyzed each time the rule runs, using a date + math range. For example, now-4200s means the rule analyzes data from 70 + minutes before its start time. Defaults to now-6m (analyzes data from 6 + minutes before the start time). format: date-math type: string RuleIntervalTo: @@ -3779,6 +4315,37 @@ components: - $ref: '#/components/schemas/MachineLearningRulePatchProps' - $ref: '#/components/schemas/NewTermsRulePatchProps' - $ref: '#/components/schemas/EsqlRulePatchProps' + RulePreviewLogs: + type: object + properties: + duration: + description: Execution duration in milliseconds + type: integer + errors: + items: + $ref: '#/components/schemas/NonEmptyString' + type: array + startedAt: + $ref: '#/components/schemas/NonEmptyString' + warnings: + items: + $ref: '#/components/schemas/NonEmptyString' + type: array + required: + - errors + - warnings + - duration + RulePreviewParams: + type: object + properties: + invocationCount: + type: integer + timeframeEnd: + format: date-time + type: string + required: + - invocationCount + - timeframeEnd RuleQuery: type: string RuleReferenceArray: @@ -4303,6 +4870,36 @@ components: - risk_score - severity - $ref: '#/components/schemas/SavedQueryRuleCreateFields' + SetAlertsStatusByIds: + type: object + properties: + signal_ids: + items: + $ref: '#/components/schemas/NonEmptyString' + minItems: 1 + type: array + status: + $ref: '#/components/schemas/AlertStatus' + required: + - signal_ids + - status + SetAlertsStatusByQuery: + type: object + properties: + conflicts: + default: abort + enum: + - abort + - proceed + type: string + query: + additionalProperties: true + type: object + status: + $ref: '#/components/schemas/AlertStatus' + required: + - query + - status SetupGuide: type: string Severity: @@ -4334,6 +4931,16 @@ components: - severity - value type: array + SiemErrorResponse: + type: object + properties: + message: + type: string + status_code: + type: integer + required: + - status_code + - message SortOrder: enum: - asc @@ -4876,7 +5483,7 @@ components: - severity - $ref: '#/components/schemas/ThreatMatchRuleCreateFields' ThreatQuery: - description: Query to execute + description: Query to run type: string ThreatSubtechnique: type: object @@ -5483,3 +6090,4 @@ components: type: http security: - BasicAuth: [] +tags: ! '' diff --git a/x-pack/plugins/security_solution/public/app/home/global_header/index.test.tsx b/x-pack/plugins/security_solution/public/app/home/global_header/index.test.tsx index 966e13358d145..79fd89d65949d 100644 --- a/x-pack/plugins/security_solution/public/app/home/global_header/index.test.tsx +++ b/x-pack/plugins/security_solution/public/app/home/global_header/index.test.tsx @@ -7,7 +7,6 @@ import React from 'react'; import { render, waitFor } from '@testing-library/react'; import { useLocation } from 'react-router-dom'; -import { useVariationMock } from '../../../common/components/utils.mocks'; import { GlobalHeader } from '.'; import { ADD_DATA_PATH, @@ -60,10 +59,6 @@ describe('global header', () => { }; const store = createMockStore(state); - beforeEach(() => { - useVariationMock.mockReset(); - }); - it('has add data link', () => { (useLocation as jest.Mock).mockReturnValue([ { pageName: SecurityPageName.overview, detailName: undefined }, @@ -100,26 +95,6 @@ describe('global header', () => { expect(link?.getAttribute('href')).toBe(ADD_THREAT_INTELLIGENCE_DATA_PATH); }); - it('points to the resolved Add data URL by useVariation', () => { - (useLocation as jest.Mock).mockReturnValue([ - { pageName: SecurityPageName.overview, detailName: undefined }, - ]); - - const customResolvedUrl = '/test/url'; - useVariationMock.mockImplementationOnce( - (cloudExperiments, featureFlagName, defaultValue, setter) => { - setter(customResolvedUrl); - } - ); - const { queryByTestId } = render( - - - - ); - const link = queryByTestId('add-data'); - expect(link?.getAttribute('href')).toBe(customResolvedUrl); - }); - it.each(sourcererPaths)('shows sourcerer on %s page', (pathname) => { (useLocation as jest.Mock).mockReturnValue({ pathname }); diff --git a/x-pack/plugins/security_solution/public/assistant/stack_management/management_settings.tsx b/x-pack/plugins/security_solution/public/assistant/stack_management/management_settings.tsx index 31f3910fdab49..2855c6b6115d3 100644 --- a/x-pack/plugins/security_solution/public/assistant/stack_management/management_settings.tsx +++ b/x-pack/plugins/security_solution/public/assistant/stack_management/management_settings.tsx @@ -31,11 +31,7 @@ export const ManagementSettings = React.memo(() => { mergeBaseWithPersistedConversations(baseConversations, conversationsData), [baseConversations] ); - const { - data: conversations, - isFetched: conversationsLoaded, - refetch: refetchConversations, - } = useFetchCurrentUserConversations({ + const { data: conversations } = useFetchCurrentUserConversations({ http, onFetch: onFetchedConversations, isAssistantEnabled, @@ -51,14 +47,7 @@ export const ManagementSettings = React.memo(() => { ); if (conversations) { - return ( - - ); + return ; } return <>; diff --git a/x-pack/plugins/security_solution/public/attack_discovery/pages/empty_states/index.test.tsx b/x-pack/plugins/security_solution/public/attack_discovery/pages/empty_states/index.test.tsx index 460511defbdf9..3b5b87ada83ec 100644 --- a/x-pack/plugins/security_solution/public/attack_discovery/pages/empty_states/index.test.tsx +++ b/x-pack/plugins/security_solution/public/attack_discovery/pages/empty_states/index.test.tsx @@ -143,6 +143,52 @@ describe('EmptyStates', () => { }); }); + describe('when the Failure prompt should NOT be shown, because loading is true', () => { + beforeEach(() => { + jest.clearAllMocks(); + + const aiConnectorsCount = 1; + const alertsContextCount = 10; + const alertsCount = 10; + const attackDiscoveriesCount = 10; + const connectorId = 'test-connector-id'; + const failureReason = 'this failure should NOT be displayed, because we are loading'; // <-- failureReason is provided + const isLoading = true; // <-- loading data + const onGenerate = jest.fn(); + + render( + + + + ); + }); + + it('does NOT render the Welcome prompt', () => { + expect(screen.queryByTestId('welcome')).not.toBeInTheDocument(); + }); + + it('does NOT render the Failure prompt', () => { + expect(screen.queryByTestId('failure')).not.toBeInTheDocument(); + }); + + it('does NOT render the No Alerts prompt', () => { + expect(screen.queryByTestId('noAlerts')).not.toBeInTheDocument(); + }); + + it('does NOT render the Empty prompt', () => { + expect(screen.queryByTestId('emptyPrompt')).not.toBeInTheDocument(); + }); + }); + describe('when the Empty prompt should be shown', () => { beforeEach(() => { jest.clearAllMocks(); @@ -188,6 +234,51 @@ describe('EmptyStates', () => { }); }); + describe('when the Empty prompt should NOT be shown, because aiConnectorsCount is null (no connectors are configured)', () => { + beforeEach(() => { + jest.clearAllMocks(); + + const aiConnectorsCount = null; // <-- no connectors configured + const alertsContextCount = 20; // <-- alerts were sent as context to be analyzed + const alertsCount = 0; + const attackDiscoveriesCount = 0; + const connectorId = undefined; + const isLoading = false; + const onGenerate = jest.fn(); + + render( + + + + ); + }); + + it('does NOT render the Welcome prompt', () => { + expect(screen.queryByTestId('welcome')).not.toBeInTheDocument(); + }); + + it('does NOT render the Failure prompt', () => { + expect(screen.queryByTestId('failure')).not.toBeInTheDocument(); + }); + + it('does NOT render the No Alerts prompt', () => { + expect(screen.queryByTestId('noAlerts')).not.toBeInTheDocument(); + }); + + it('does NOT render the Empty prompt', () => { + expect(screen.queryByTestId('emptyPrompt')).not.toBeInTheDocument(); + }); + }); + describe('when loading', () => { let result: ReturnType; diff --git a/x-pack/plugins/security_solution/public/attack_discovery/pages/empty_states/index.tsx b/x-pack/plugins/security_solution/public/attack_discovery/pages/empty_states/index.tsx index d38200a4be205..49b4557c72192 100644 --- a/x-pack/plugins/security_solution/public/attack_discovery/pages/empty_states/index.tsx +++ b/x-pack/plugins/security_solution/public/attack_discovery/pages/empty_states/index.tsx @@ -36,11 +36,11 @@ const EmptyStatesComponent: React.FC = ({ }) => { if (showWelcomePrompt({ aiConnectorsCount, isLoading })) { return ; - } else if (failureReason !== null) { + } else if (!isLoading && failureReason != null) { return ; } else if (showNoAlertsPrompt({ alertsContextCount, isLoading })) { return ; - } else if (showEmptyPrompt({ attackDiscoveriesCount, isLoading })) { + } else if (showEmptyPrompt({ aiConnectorsCount, attackDiscoveriesCount, isLoading })) { return ( { expect(learnMoreLink).toHaveTextContent(LEARN_MORE); }); }); + + describe('error text formatting', () => { + it('allows errors containing long strings of text, e.g. alert IDs, to wrap when necessary', () => { + const bodyText = screen.getByTestId('bodyText'); + + expect(bodyText).toHaveStyle('word-wrap: break-word'); + }); + }); }); diff --git a/x-pack/plugins/security_solution/public/attack_discovery/pages/failure/index.tsx b/x-pack/plugins/security_solution/public/attack_discovery/pages/failure/index.tsx index 8de3e0e380c07..4318f3f78536a 100644 --- a/x-pack/plugins/security_solution/public/attack_discovery/pages/failure/index.tsx +++ b/x-pack/plugins/security_solution/public/attack_discovery/pages/failure/index.tsx @@ -6,6 +6,7 @@ */ import { EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem, EuiLink, EuiText } from '@elastic/eui'; +import { css } from '@emotion/react'; import React from 'react'; import * as i18n from './translations'; @@ -18,7 +19,13 @@ const FailureComponent: React.FC<{ failureReason: string }> = ({ failureReason } iconType="error" color="danger" body={ - + {failureReason} } diff --git a/x-pack/plugins/security_solution/public/attack_discovery/pages/helpers.test.ts b/x-pack/plugins/security_solution/public/attack_discovery/pages/helpers.test.ts index ed6ec50ad908c..e94687611ea8f 100644 --- a/x-pack/plugins/security_solution/public/attack_discovery/pages/helpers.test.ts +++ b/x-pack/plugins/security_solution/public/attack_discovery/pages/helpers.test.ts @@ -87,6 +87,7 @@ describe('helpers', () => { describe('showEmptyPrompt', () => { it('returns true when isLoading is false and attackDiscoveriesCount is 0', () => { const result = showEmptyPrompt({ + aiConnectorsCount: 1, attackDiscoveriesCount: 0, isLoading: false, }); @@ -94,8 +95,29 @@ describe('helpers', () => { expect(result).toBe(true); }); + it('returns false when isLoading is false and attackDiscoveriesCount is 0 and aiConnectorsCount is null', () => { + const result = showEmptyPrompt({ + aiConnectorsCount: null, + attackDiscoveriesCount: 0, + isLoading: false, + }); + + expect(result).toBe(false); + }); + it('returns false when isLoading is true', () => { const result = showEmptyPrompt({ + aiConnectorsCount: 1, + attackDiscoveriesCount: 0, + isLoading: true, + }); + + expect(result).toBe(false); + }); + + it('returns false when isLoading is true and aiConnectorsCount is null', () => { + const result = showEmptyPrompt({ + aiConnectorsCount: null, attackDiscoveriesCount: 0, isLoading: true, }); @@ -105,6 +127,17 @@ describe('helpers', () => { it('returns false when attackDiscoveriesCount is greater than 0', () => { const result = showEmptyPrompt({ + aiConnectorsCount: 1, + attackDiscoveriesCount: 4, + isLoading: false, + }); + + expect(result).toBe(false); + }); + + it('returns false when attackDiscoveriesCount is greater than 0 and aiConnectorsCount is null', () => { + const result = showEmptyPrompt({ + aiConnectorsCount: null, attackDiscoveriesCount: 4, isLoading: false, }); diff --git a/x-pack/plugins/security_solution/public/attack_discovery/pages/helpers.ts b/x-pack/plugins/security_solution/public/attack_discovery/pages/helpers.ts index e14aa1a5a049f..e3d3be963bacd 100644 --- a/x-pack/plugins/security_solution/public/attack_discovery/pages/helpers.ts +++ b/x-pack/plugins/security_solution/public/attack_discovery/pages/helpers.ts @@ -90,12 +90,14 @@ export const showWelcomePrompt = ({ }): boolean => !isLoading && aiConnectorsCount != null && aiConnectorsCount === 0; export const showEmptyPrompt = ({ + aiConnectorsCount, attackDiscoveriesCount, isLoading, }: { + aiConnectorsCount: number | null; attackDiscoveriesCount: number; isLoading: boolean; -}): boolean => !isLoading && attackDiscoveriesCount === 0; +}): boolean => !isLoading && aiConnectorsCount != null && attackDiscoveriesCount === 0; export const showLoading = ({ connectorId, diff --git a/x-pack/plugins/security_solution/public/attack_discovery/pages/index.test.tsx b/x-pack/plugins/security_solution/public/attack_discovery/pages/index.test.tsx index ff4e420e0e360..f27f8d448bbd3 100644 --- a/x-pack/plugins/security_solution/public/attack_discovery/pages/index.test.tsx +++ b/x-pack/plugins/security_solution/public/attack_discovery/pages/index.test.tsx @@ -14,6 +14,7 @@ import { UpsellingService } from '@kbn/security-solution-upselling/service'; import { Router } from '@kbn/shared-ux-router'; import { render, screen } from '@testing-library/react'; import React from 'react'; +import { useLocalStorage } from 'react-use'; import { TestProviders } from '../../common/mock'; import { MockAssistantProvider } from '../../common/mock/mock_assistant_provider'; @@ -29,13 +30,22 @@ import { } from '../mock/mock_use_attack_discovery'; import { ATTACK_DISCOVERY_PAGE_TITLE } from './page_title/translations'; import { useAttackDiscovery } from '../use_attack_discovery'; +import { useLoadConnectors } from '@kbn/elastic-assistant/impl/connectorland/use_load_connectors'; + +const mockConnectors: unknown[] = [ + { + id: 'test-id', + name: 'OpenAI connector', + actionTypeId: '.gen-ai', + }, +]; jest.mock('react-use', () => { const actual = jest.requireActual('react-use'); return { ...actual, - useLocalStorage: jest.fn().mockReturnValue([undefined, jest.fn()]), + useLocalStorage: jest.fn().mockReturnValue(['test-id', jest.fn()]), useSessionStorage: jest.fn().mockReturnValue([undefined, jest.fn()]), }; }); @@ -47,6 +57,20 @@ jest.mock( }) ); +jest.mock('@kbn/elastic-assistant/impl/connectorland/use_load_connectors', () => ({ + useLoadConnectors: jest.fn(() => ({ + isFetched: true, + data: mockConnectors, + })), +})); + +jest.mock( + '@kbn/elastic-assistant/impl/connectorland/connector_selector_inline/connector_selector_inline', + () => ({ + ConnectorSelectorInline: () => null, + }) +); + jest.mock('../../common/links', () => ({ useLinkInfo: jest.fn().mockReturnValue({ capabilities: ['siem.show'], @@ -186,6 +210,13 @@ const historyMock = { describe('AttackDiscovery', () => { beforeEach(() => { jest.clearAllMocks(); + + (useLoadConnectors as jest.Mock).mockReturnValue({ + isFetched: true, + data: mockConnectors, + }); + + (useLocalStorage as jest.Mock).mockReturnValue(['test-id', jest.fn()]); }); describe('page layout', () => { @@ -225,6 +256,10 @@ describe('AttackDiscovery', () => { ); }); + it('does NOT render the animated logo', () => { + expect(screen.queryByTestId('animatedLogo')).toBeNull(); + }); + it('does NOT render the summary', () => { expect(screen.queryByTestId('summary')).toBeNull(); }); @@ -246,6 +281,190 @@ describe('AttackDiscovery', () => { }); }); + describe('when connectors are configured and didInitialFetch is false', () => { + beforeEach(() => { + (useAttackDiscovery as jest.Mock).mockReturnValue({ + approximateFutureTime: null, + attackDiscoveries: [], + cachedAttackDiscoveries: {}, + didInitialFetch: false, // <-- didInitialFetch is false + fetchAttackDiscoveries: jest.fn(), + failureReason: null, + generationIntervals: undefined, + isLoading: false, + isLoadingPost: false, + lastUpdated: null, + replacements: {}, + }); + + render( + + + + + + + + ); + }); + + it('renders the animated logo, because connectors are configured and the initial fetch is pending', () => { + expect(screen.getByTestId('animatedLogo')).toBeInTheDocument(); + }); + + it('does NOT render the summary', () => { + expect(screen.queryByTestId('summary')).toBeNull(); + }); + + it('does NOT render the loading callout', () => { + expect(screen.queryByTestId('loadingCallout')).toBeNull(); + }); + + it('does NOT render the empty prompt', () => { + expect(screen.queryByTestId('emptyPrompt')).toBeNull(); + }); + + it('does NOT render attack discoveries', () => { + expect(screen.queryAllByTestId('attackDiscovery')).toHaveLength(0); + }); + + it('does NOT render the upgrade call to action', () => { + expect(screen.queryByTestId('upgrade')).toBeNull(); + }); + }); + + describe('when connectors are configured, connectorId is undefined, and didInitialFetch is false', () => { + // At least two connectors are required for this scenario, + // because a single connector will be automatically selected, + // which will set connectorId to a non-undefined value: + const multipleMockConnectors: unknown[] = [ + { + id: 'mock-connector-1', + name: 'OpenAI connector 1', + actionTypeId: '.gen-ai', + }, + { + id: 'mock-connector-2', + name: 'OpenAI connector 2', + actionTypeId: '.gen-ai', + }, + ]; + + beforeEach(() => { + (useLoadConnectors as jest.Mock).mockReturnValue({ + isFetched: true, + data: multipleMockConnectors, // <-- multiple connectors, so none are auto-selected + }); + + (useLocalStorage as jest.Mock).mockReturnValue([undefined, jest.fn()]); // <-- connectorId is undefined + + (useAttackDiscovery as jest.Mock).mockReturnValue({ + approximateFutureTime: null, + attackDiscoveries: [], + cachedAttackDiscoveries: {}, + didInitialFetch: false, // <-- didInitialFetch is false + fetchAttackDiscoveries: jest.fn(), + failureReason: null, + generationIntervals: undefined, + isLoading: false, + isLoadingPost: false, + lastUpdated: null, + replacements: {}, + }); + + render( + + + + + + + + ); + }); + + it('does NOT render the animated logo, because connectorId is undefined', () => { + expect(screen.queryByTestId('animatedLogo')).toBeNull(); + }); + + it('does NOT render the summary', () => { + expect(screen.queryByTestId('summary')).toBeNull(); + }); + + it('does NOT render the loading callout', () => { + expect(screen.queryByTestId('loadingCallout')).toBeNull(); + }); + + it('renders the empty prompt', () => { + expect(screen.getByTestId('emptyPrompt')).toBeInTheDocument(); + }); + + it('does NOT render attack discoveries', () => { + expect(screen.queryAllByTestId('attackDiscovery')).toHaveLength(0); + }); + + it('does NOT render the upgrade call to action', () => { + expect(screen.queryByTestId('upgrade')).toBeNull(); + }); + }); + + describe('when connectors are NOT configured and didInitialFetch is false', () => { + beforeEach(() => { + (useLoadConnectors as jest.Mock).mockReturnValue({ + isFetched: true, + data: [], // <-- connectors are NOT configured + }); + + (useAttackDiscovery as jest.Mock).mockReturnValue({ + approximateFutureTime: null, + attackDiscoveries: [], + cachedAttackDiscoveries: {}, + didInitialFetch: false, // <-- didInitialFetch is false + fetchAttackDiscoveries: jest.fn(), + failureReason: null, + generationIntervals: undefined, + isLoading: false, + isLoadingPost: false, + lastUpdated: null, + replacements: {}, + }); + + render( + + + + + + + + ); + }); + + it('does NOT render the animated logo, because connectors are NOT configured', () => { + expect(screen.queryByTestId('animatedLogo')).toBeNull(); + }); + + it('does NOT render the summary', () => { + expect(screen.queryByTestId('summary')).toBeNull(); + }); + + it('does NOT render the loading callout', () => { + expect(screen.queryByTestId('loadingCallout')).toBeNull(); + }); + + it('does NOT render the empty prompt', () => { + expect(screen.queryByTestId('emptyPrompt')).toBeNull(); + }); + + it('does NOT render attack discoveries', () => { + expect(screen.queryAllByTestId('attackDiscovery')).toHaveLength(0); + }); + + it('does NOT render the upgrade call to action', () => { + expect(screen.queryByTestId('upgrade')).toBeNull(); + }); + }); + describe('when there are attack discoveries', () => { const mockUseAttackDiscoveriesResults = getMockUseAttackDiscoveriesWithCachedAttackDiscoveries( jest.fn() @@ -266,6 +485,10 @@ describe('AttackDiscovery', () => { ); }); + it('does NOT render the animated logo', () => { + expect(screen.queryByTestId('animatedLogo')).toBeNull(); + }); + it('renders the summary', () => { expect(screen.getByTestId('summary')).toBeInTheDocument(); }); @@ -304,6 +527,10 @@ describe('AttackDiscovery', () => { ); }); + it('does NOT render the animated logo, because didInitialFetch is true', () => { + expect(screen.queryByTestId('animatedLogo')).toBeNull(); + }); + it('does NOT render the summary', () => { expect(screen.queryByTestId('summary')).toBeNull(); }); @@ -348,6 +575,10 @@ describe('AttackDiscovery', () => { ); }); + it('does NOT render the animated logo', () => { + expect(screen.queryByTestId('animatedLogo')).toBeNull(); + }); + it('does NOT render the header', () => { expect(screen.queryByTestId('header')).toBeNull(); }); diff --git a/x-pack/plugins/security_solution/public/attack_discovery/pages/index.tsx b/x-pack/plugins/security_solution/public/attack_discovery/pages/index.tsx index a3784311983cb..9a5c311b5494f 100644 --- a/x-pack/plugins/security_solution/public/attack_discovery/pages/index.tsx +++ b/x-pack/plugins/security_solution/public/attack_discovery/pages/index.tsx @@ -136,9 +136,15 @@ const AttackDiscoveryPageComponent: React.FC = () => { // If there is only one connector, set it as the selected connector if (aiConnectors != null && aiConnectors.length === 1) { setConnectorId(aiConnectors[0].id); + } else if (aiConnectors != null && aiConnectors.length === 0) { + // connectors have been removed, reset the connectorId and cached Attack discoveries + setConnectorId(undefined); + setSelectedConnectorAttackDiscoveries([]); } - }, [aiConnectors, setConnectorId]); + }, [aiConnectors]); + const animatedLogo = useMemo(() => , []); + const connectorsAreConfigured = aiConnectors != null && aiConnectors.length > 0; const attackDiscoveriesCount = selectedConnectorAttackDiscoveries.length; if (!isAssistantEnabled) { @@ -166,7 +172,7 @@ const AttackDiscoveryPageComponent: React.FC = () => {
    0} + connectorsAreConfigured={connectorsAreConfigured} isLoading={isLoading} // disable header actions before post request has completed isDisabledActions={isLoadingPost} @@ -177,8 +183,8 @@ const AttackDiscoveryPageComponent: React.FC = () => { /> - {!didInitialFetch ? ( - } /> + {connectorsAreConfigured && connectorId != null && !didInitialFetch ? ( + ) : ( <> {showSummary({ diff --git a/x-pack/plugins/security_solution/public/common/components/avc_banner/avc_banner_background.svg b/x-pack/plugins/security_solution/public/common/components/avc_banner/avc_banner_background.svg deleted file mode 100644 index cd37f26c95f7b..0000000000000 --- a/x-pack/plugins/security_solution/public/common/components/avc_banner/avc_banner_background.svg +++ /dev/null @@ -1,329 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/x-pack/plugins/security_solution/public/common/components/discover_in_timeline/use_discover_in_timeline_actions.tsx b/x-pack/plugins/security_solution/public/common/components/discover_in_timeline/use_discover_in_timeline_actions.tsx index 7a6756bfe80ac..f317f6ded4b15 100644 --- a/x-pack/plugins/security_solution/public/common/components/discover_in_timeline/use_discover_in_timeline_actions.tsx +++ b/x-pack/plugins/security_solution/public/common/components/discover_in_timeline/use_discover_in_timeline_actions.tsx @@ -28,6 +28,20 @@ import { DISCOVER_SEARCH_SAVE_ERROR_UNKNOWN, } from './translations'; +function defaultDiscoverAppState(): DiscoverAppState { + return { + query: { + esql: '', + }, + sort: [['@timestamp', 'desc']], + columns: [], + interval: 'auto', + filters: [], + hideChart: true, + grid: {}, + }; +} + export const defaultDiscoverTimeRange: TimeRange = { from: 'now-15m', to: 'now', @@ -80,20 +94,6 @@ export const useDiscoverInTimelineActions = ( mutationKey: [version], }); - const defaultDiscoverAppState: DiscoverAppState = useMemo(() => { - return { - query: { - esql: '', - }, - sort: [['@timestamp', 'desc']], - columns: [], - interval: 'auto', - filters: [], - hideChart: true, - grid: {}, - }; - }, []); - /* * generates Appstate from a given saved Search object * @@ -129,7 +129,7 @@ export const useDiscoverInTimelineActions = ( await discoverStateContainer.current?.appState.replaceUrlState( savedSearchState?.appState ?? {} ); - setDiscoverAppState(savedSearchState?.appState ?? defaultDiscoverAppState); + setDiscoverAppState(savedSearchState?.appState ?? defaultDiscoverAppState()); discoverStateContainer.current?.globalState.set({ ...discoverStateContainer.current?.globalState.get(), time: savedSearch.timeRange ?? defaultDiscoverTimeRange, @@ -138,21 +138,17 @@ export const useDiscoverInTimelineActions = ( /* empty */ } } else { - discoverStateContainer.current?.appState.resetToState(defaultDiscoverAppState); + const defaultState = defaultDiscoverAppState(); + discoverStateContainer.current?.appState.resetToState(defaultState); await discoverStateContainer.current?.appState.replaceUrlState({}); - setDiscoverAppState(defaultDiscoverAppState); + setDiscoverAppState(defaultState); discoverStateContainer.current?.globalState.set({ ...discoverStateContainer.current?.globalState.get(), time: defaultDiscoverTimeRange, }); } }, - [ - defaultDiscoverAppState, - discoverStateContainer, - getAppStateFromSavedSearch, - setDiscoverAppState, - ] + [discoverStateContainer, getAppStateFromSavedSearch, setDiscoverAppState] ); const persistSavedSearch = useCallback( @@ -276,14 +272,13 @@ export const useDiscoverInTimelineActions = ( updateSavedSearch, initializeLocalSavedSearch, getAppStateFromSavedSearch, - defaultDiscoverAppState, + defaultDiscoverAppState: defaultDiscoverAppState(), }), [ resetDiscoverAppState, updateSavedSearch, initializeLocalSavedSearch, getAppStateFromSavedSearch, - defaultDiscoverAppState, ] ); diff --git a/x-pack/plugins/security_solution/public/common/components/landing_page/onboarding/onboarding.tsx b/x-pack/plugins/security_solution/public/common/components/landing_page/onboarding/onboarding.tsx index c19f03f63461d..571d4e59a89e6 100644 --- a/x-pack/plugins/security_solution/public/common/components/landing_page/onboarding/onboarding.tsx +++ b/x-pack/plugins/security_solution/public/common/components/landing_page/onboarding/onboarding.tsx @@ -6,6 +6,7 @@ */ import React, { useCallback, useMemo, useState } from 'react'; +import { AVCResultsBanner2024 } from '@kbn/avc-banner'; import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; import { TogglePanel } from './toggle_panel'; @@ -24,7 +25,6 @@ import type { StepId } from './types'; import { useOnboardingStyles } from './styles/onboarding.styles'; import { useKibana } from '../../../lib/kibana'; import type { OnboardingHubStepLinkClickedParams } from '../../../lib/telemetry/events/onboarding/types'; -import { AVCResultsBanner2024 } from '../../avc_banner/avc_results_banner_2024'; interface OnboardingProps { indicesExist?: boolean; diff --git a/x-pack/plugins/security_solution/public/common/components/tables/__snapshots__/helpers.test.tsx.snap b/x-pack/plugins/security_solution/public/common/components/tables/__snapshots__/helpers.test.tsx.snap index 8960e2ad819b2..c91ece7818df0 100644 --- a/x-pack/plugins/security_solution/public/common/components/tables/__snapshots__/helpers.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/common/components/tables/__snapshots__/helpers.test.tsx.snap @@ -18,25 +18,36 @@ exports[`Table Helpers #RowItemOverflow it returns correctly against snapshot 1` Array [ "item1", "item2", - "item3", ] } /> -

    - - 1 - - - -

    + + + + + 1 + + + + + + `; diff --git a/x-pack/plugins/security_solution/public/common/components/tables/helpers.test.tsx b/x-pack/plugins/security_solution/public/common/components/tables/helpers.test.tsx index 852bf3759fa04..61314f1326db5 100644 --- a/x-pack/plugins/security_solution/public/common/components/tables/helpers.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/tables/helpers.test.tsx @@ -107,8 +107,8 @@ describe('Table Helpers', () => { values={items} fieldName="attrName" idPrefix="idPrefix" - maxOverflowItems={1} overflowIndexStart={1} + maxOverflowItems={1} /> ); expect(wrapper).toMatchSnapshot(); @@ -159,6 +159,26 @@ describe('Table Helpers', () => { ); expect(wrapper.find('[data-test-subj="popover-additional-overflow"]').length).toBe(1); }); + + test('it shows correct number of overflow items when maxOverflowItems are exceeded', () => { + const wrapper = mount( + + + + ); + wrapper.find('[data-test-subj="overflow-button"]').first().find('button').simulate('click'); + + expect( + wrapper.find('[data-test-subj="overflow-items"]').last().prop('children') + ?.length + ).toBe(1); + }); }); describe('OverflowField', () => { diff --git a/x-pack/plugins/security_solution/public/common/components/tables/helpers.tsx b/x-pack/plugins/security_solution/public/common/components/tables/helpers.tsx index 4d8dd866e3075..2c21ffa8cbd70 100644 --- a/x-pack/plugins/security_solution/public/common/components/tables/helpers.tsx +++ b/x-pack/plugins/security_solution/public/common/components/tables/helpers.tsx @@ -4,15 +4,24 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useCallback, useState } from 'react'; +import React, { useCallback, useMemo, useState } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; -import { EuiLink, EuiPopover, EuiToolTip, EuiText, EuiTextColor } from '@elastic/eui'; +import { euiThemeVars } from '@kbn/ui-theme'; +import { + EuiLink, + EuiPopover, + EuiToolTip, + EuiText, + EuiTextColor, + EuiFlexGroup, + EuiFlexItem, +} from '@elastic/eui'; import styled from 'styled-components'; import { SecurityCellActions, CellActionsMode, SecurityCellActionsTrigger } from '../cell_actions'; import { escapeDataProviderId } from '../drag_and_drop/helpers'; import { defaultToEmptyTag, getEmptyTagValue } from '../empty_value'; import { MoreRowItems } from '../page'; -import { MoreContainer } from '../../../timelines/components/field_renderers/field_renderers'; +import { MoreContainer } from '../../../timelines/components/field_renderers/more_container'; const Subtext = styled.div` font-size: ${(props) => props.theme.eui.euiFontSizeXS}; @@ -62,8 +71,8 @@ export const getRowItemsWithActions = ({ fieldName={fieldName} values={values} idPrefix={idPrefix} - maxOverflowItems={maxOverflow} overflowIndexStart={displayCount} + maxOverflowItems={maxOverflow} /> ) : ( @@ -78,17 +87,21 @@ interface RowItemOverflowProps { fieldName: string; values: string[]; idPrefix: string; - maxOverflowItems: number; overflowIndexStart: number; + maxOverflowItems: number; } export const RowItemOverflowComponent: React.FC = ({ fieldName, values, idPrefix, - maxOverflowItems = 5, overflowIndexStart = 5, + maxOverflowItems = 5, }) => { + const maxVisibleValues = useMemo( + () => values.slice(0, maxOverflowItems + 1), + [values, maxOverflowItems] + ); return ( <> {values.length > overflowIndexStart && ( @@ -97,23 +110,30 @@ export const RowItemOverflowComponent: React.FC = ({ - - {values.length > overflowIndexStart + maxOverflowItems && ( -

    - - {values.length - overflowIndexStart - maxOverflowItems}{' '} - - -

    - )} + {values.length > overflowIndexStart + maxOverflowItems && ( + + + + + {values.length - overflowIndexStart - maxOverflowItems}{' '} + + + + + + )} )} diff --git a/x-pack/plugins/security_solution/public/common/components/utils.mocks.tsx b/x-pack/plugins/security_solution/public/common/components/utils.mocks.tsx deleted file mode 100644 index 8d3f21984aefe..0000000000000 --- a/x-pack/plugins/security_solution/public/common/components/utils.mocks.tsx +++ /dev/null @@ -1,18 +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 { useVariation } from './utils'; - -export const useVariationMock: jest.MockedFunction = jest.fn(); - -jest.doMock('./utils', () => { - const actualUtils = jest.requireActual('./utils'); - return { - ...actualUtils, - useVariation: useVariationMock, - }; -}); diff --git a/x-pack/plugins/security_solution/public/common/components/utils.test.ts b/x-pack/plugins/security_solution/public/common/components/utils.test.ts deleted file mode 100644 index 7a5cbecdd534a..0000000000000 --- a/x-pack/plugins/security_solution/public/common/components/utils.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { renderHook } from '@testing-library/react-hooks'; -import { cloudExperimentsMock } from '@kbn/cloud-experiments-plugin/common/mocks'; -import { useVariation } from './utils'; - -describe('useVariation', () => { - test('it should call the setter if cloudExperiments is enabled', async () => { - const cloudExperiments = cloudExperimentsMock.createStartMock(); - cloudExperiments.getVariation.mockResolvedValue('resolved value'); - const setter = jest.fn(); - const { result } = renderHook(() => - useVariation( - cloudExperiments, - 'security-solutions.add-integrations-url', - 'my default value', - setter - ) - ); - await new Promise((resolve) => process.nextTick(resolve)); - expect(result.error).toBe(undefined); - expect(setter).toHaveBeenCalledTimes(1); - expect(setter).toHaveBeenCalledWith('resolved value'); - }); - - test('it should not call the setter if cloudExperiments is not enabled', async () => { - const setter = jest.fn(); - const { result } = renderHook(() => - useVariation(undefined, 'security-solutions.add-integrations-url', 'my default value', setter) - ); - await new Promise((resolve) => process.nextTick(resolve)); - expect(result.error).toBe(undefined); - expect(setter).not.toHaveBeenCalled(); - }); -}); diff --git a/x-pack/plugins/security_solution/public/common/components/utils.ts b/x-pack/plugins/security_solution/public/common/components/utils.ts index a850553bf2d93..abe74b8830bd3 100644 --- a/x-pack/plugins/security_solution/public/common/components/utils.ts +++ b/x-pack/plugins/security_solution/public/common/components/utils.ts @@ -6,14 +6,10 @@ */ import { throttle } from 'lodash/fp'; -import { useEffect, useMemo, useState } from 'react'; +import { useMemo, useState } from 'react'; import useResizeObserver from 'use-resize-observer/polyfilled'; import { niceTimeFormatByDay, timeFormatter } from '@elastic/charts'; import moment from 'moment-timezone'; -import type { - CloudExperimentsFeatureFlagNames, - CloudExperimentsPluginStart, -} from '@kbn/cloud-experiments-plugin/common'; export const getDaysDiff = (minDate: moment.Moment, maxDate: moment.Moment) => { const diff = maxDate.diff(minDate, 'days'); @@ -39,26 +35,3 @@ export const useThrottledResizeObserver = (wait = 100) => { return { ref, ...size }; }; - -/** - * Retrieves the variation of the feature flag if the cloudExperiments plugin is enabled. - * @param cloudExperiments {@link CloudExperimentsPluginStart} - * @param featureFlagName The name of the feature flag {@link CloudExperimentsFeatureFlagNames} - * @param defaultValue The default value in case it cannot retrieve the feature flag - * @param setter The setter from {@link useState} to update the value. - */ -export const useVariation = ( - cloudExperiments: CloudExperimentsPluginStart | undefined, - featureFlagName: CloudExperimentsFeatureFlagNames, - defaultValue: Data, - setter: (value: Data) => void -) => { - useEffect(() => { - (async function loadVariation() { - const variationUrl = await cloudExperiments?.getVariation(featureFlagName, defaultValue); - if (variationUrl) { - setter(variationUrl); - } - })(); - }, [cloudExperiments, featureFlagName, defaultValue, setter]); -}; diff --git a/x-pack/plugins/security_solution/public/common/hooks/use_add_integrations_url.ts b/x-pack/plugins/security_solution/public/common/hooks/use_add_integrations_url.ts index 0bbedbb3adadb..07a63013b0687 100644 --- a/x-pack/plugins/security_solution/public/common/hooks/use_add_integrations_url.ts +++ b/x-pack/plugins/security_solution/public/common/hooks/use_add_integrations_url.ts @@ -4,11 +4,10 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { useCallback, useMemo, useState } from 'react'; +import { useCallback, useMemo } from 'react'; import { useLocation } from 'react-router-dom'; import { ADD_DATA_PATH, ADD_THREAT_INTELLIGENCE_DATA_PATH } from '../../../common/constants'; import { isThreatIntelligencePath } from '../../helpers'; -import { useVariation } from '../components/utils'; import { useKibana, useNavigateTo } from '../lib/kibana'; @@ -17,7 +16,6 @@ export const useAddIntegrationsUrl = () => { http: { basePath: { prepend }, }, - cloudExperiments, } = useKibana().services; const { pathname } = useLocation(); const { navigateTo } = useNavigateTo(); @@ -25,15 +23,8 @@ export const useAddIntegrationsUrl = () => { const isThreatIntelligence = isThreatIntelligencePath(pathname); const integrationsUrl = isThreatIntelligence ? ADD_THREAT_INTELLIGENCE_DATA_PATH : ADD_DATA_PATH; - const [addIntegrationsUrl, setAddIntegrationsUrl] = useState(integrationsUrl); - useVariation( - cloudExperiments, - 'security-solutions.add-integrations-url', - integrationsUrl, - setAddIntegrationsUrl - ); - const href = useMemo(() => prepend(addIntegrationsUrl), [prepend, addIntegrationsUrl]); + const href = useMemo(() => prepend(integrationsUrl), [prepend, integrationsUrl]); const onClick = useCallback( (e) => { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/translations.ts index 245924b3d7e0a..4d6dde31fd5b4 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/translations.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/translations.ts @@ -23,7 +23,7 @@ export const esqlValidationErrorMessage = (message: string) => export const ESQL_VALIDATION_MISSING_METADATA_OPERATOR_IN_QUERY_ERROR = i18n.translate( 'xpack.securitySolution.detectionEngine.esqlValidation.missingMetadataOperatorInQueryError', { - defaultMessage: `Queries that don’t use the STATS...BY function (non-aggregating queries) must include the "metadata _id, _version, _index" operator after the source command. For example: FROM logs* [metadata _id, _version, _index].`, + defaultMessage: `Queries that don’t use the STATS...BY function (non-aggregating queries) must include the "metadata _id, _version, _index" operator after the source command. For example: FROM logs* metadata _id, _version, _index.`, } ); 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 bc260da6c4046..b14e007f36754 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 @@ -100,6 +100,7 @@ const getExpectedcreateTimelineParam = ( notes: null, timeline: { ...timelineDefaults, + excludedRowRendererIds: [], dataProviders, id: TimelineId.active, indexNames: [], @@ -379,7 +380,7 @@ describe('alert actions', () => { }, eventIdToNoteIds: {}, eventType: 'all', - excludedRowRendererIds: defaultTimelineProps.timeline.excludedRowRendererIds, + excludedRowRendererIds: [], expandedDetail: {}, filters: [ { @@ -549,10 +550,13 @@ describe('alert actions', () => { getExceptionFilter: mockGetExceptionFilter, }); + const expectedTimelineProps = structuredClone(defaultTimelineProps); + expectedTimelineProps.timeline.excludedRowRendererIds = []; + expect(updateTimelineIsLoading).not.toHaveBeenCalled(); expect(mockGetExceptionFilter).not.toHaveBeenCalled(); expect(createTimeline).toHaveBeenCalledTimes(1); - expect(createTimeline).toHaveBeenCalledWith(defaultTimelineProps); + expect(createTimeline).toHaveBeenCalledWith(expectedTimelineProps); }); }); @@ -576,10 +580,13 @@ describe('alert actions', () => { getExceptionFilter: mockGetExceptionFilter, }); + const expectedTimelineProps = structuredClone(defaultTimelineProps); + expectedTimelineProps.timeline.excludedRowRendererIds = []; + expect(updateTimelineIsLoading).not.toHaveBeenCalled(); expect(mockGetExceptionFilter).not.toHaveBeenCalled(); expect(createTimeline).toHaveBeenCalledTimes(1); - expect(createTimeline).toHaveBeenCalledWith(defaultTimelineProps); + expect(createTimeline).toHaveBeenCalledWith(expectedTimelineProps); }); }); @@ -614,6 +621,7 @@ describe('alert actions', () => { ...defaultTimelineProps, timeline: { ...defaultTimelineProps.timeline, + excludedRowRendererIds: [], resolveTimelineConfig: undefined, dataProviders: [ { @@ -642,6 +650,9 @@ describe('alert actions', () => { }, }; + const expectedTimelineProps = structuredClone(defaultTimelineProps); + expectedTimelineProps.timeline.excludedRowRendererIds = []; + await sendAlertToTimelineAction({ createTimeline, ecsData: ecsDataMock, @@ -653,7 +664,7 @@ describe('alert actions', () => { expect(updateTimelineIsLoading).not.toHaveBeenCalled(); expect(mockGetExceptionFilter).not.toHaveBeenCalled(); expect(createTimeline).toHaveBeenCalledTimes(1); - expect(createTimeline).toHaveBeenCalledWith(defaultTimelineProps); + expect(createTimeline).toHaveBeenCalledWith(expectedTimelineProps); }); }); @@ -737,6 +748,7 @@ describe('alert actions', () => { ...defaultTimelineProps, timeline: { ...defaultTimelineProps.timeline, + excludedRowRendererIds: [], dataProviders: [ { and: [], @@ -890,6 +902,7 @@ describe('alert actions', () => { ...defaultTimelineProps, timeline: { ...defaultTimelineProps.timeline, + excludedRowRendererIds: [], columns: mockGetOneTimelineResult.columns, defaultColumns: defaultUdtHeaders, dataProviders: [], @@ -1043,6 +1056,7 @@ describe('alert actions', () => { ...defaultTimelineProps, timeline: { ...defaultTimelineProps.timeline, + excludedRowRendererIds: [], filters: [ { meta: { diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.tsx index b88ca5ff6ab83..8e5a25638788e 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.tsx @@ -499,6 +499,7 @@ const createThresholdTimeline = async ( notes: null, timeline: { ...timelineDefaults, + excludedRowRendererIds: [], columns: templateValues.columns ?? timelineDefaults.columns, description: `_id: ${alertDoc._id}`, filters: allFilters, @@ -655,6 +656,7 @@ const createNewTermsTimeline = async ( timeline: { ...timelineDefaults, columns: templateValues.columns ?? timelineDefaults.columns, + excludedRowRendererIds: [], description: `_id: ${alertDoc._id}`, filters: allFilters, dataProviders: templateValues.dataProviders ?? dataProviders, @@ -824,6 +826,7 @@ const createSuppressedTimeline = async ( notes: null, timeline: { ...timelineDefaults, + excludedRowRendererIds: [], columns: templateValues.columns ?? timelineDefaults.columns, description: `_id: ${alertDoc._id}`, filters: allFilters, @@ -906,6 +909,7 @@ export const sendBulkEventsToTimelineAction = async ( notes: null, timeline: { ...timelineDefaults, + excludedRowRendererIds: [], dataProviders, id: TimelineId.active, indexNames: [], @@ -1050,6 +1054,7 @@ export const sendAlertToTimelineAction = async ({ from, timeline: { ...timeline, + excludedRowRendererIds: [], title: '', timelineType: TimelineType.default, templateTimelineId: null, @@ -1126,6 +1131,7 @@ export const sendAlertToTimelineAction = async ({ notes: null, timeline: { ...timelineDefaults, + excludedRowRendererIds: [], dataProviders, id: TimelineId.active, indexNames: [], 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 aa94c0f076f46..786708263fa74 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 @@ -163,9 +163,10 @@ export const useInvestigateInTimeline = ({ columns: !unifiedComponentsInTimelineDisabled ? defaultUdtHeaders : defaultHeaders, indexNames: timeline.indexNames ?? [], show: true, - excludedRowRendererIds: !unifiedComponentsInTimelineDisabled - ? timeline.excludedRowRendererIds - : [], + excludedRowRendererIds: + !unifiedComponentsInTimelineDisabled && timeline.timelineType !== TimelineType.template + ? timeline.excludedRowRendererIds + : [], }, to: toTimeline, ruleNote, diff --git a/x-pack/plugins/security_solution/public/explore/network/components/embeddables/map_tool_tip/point_tool_tip_content.tsx b/x-pack/plugins/security_solution/public/explore/network/components/embeddables/map_tool_tip/point_tool_tip_content.tsx index 01f6641133dad..43f874dec5215 100644 --- a/x-pack/plugins/security_solution/public/explore/network/components/embeddables/map_tool_tip/point_tool_tip_content.tsx +++ b/x-pack/plugins/security_solution/public/explore/network/components/embeddables/map_tool_tip/point_tool_tip_content.tsx @@ -14,7 +14,7 @@ import { } from '../../../../../common/components/empty_value'; import { DescriptionListStyled } from '../../../../../common/components/page'; import { HostDetailsLink, NetworkDetailsLink } from '../../../../../common/components/links'; -import { DefaultFieldRenderer } from '../../../../../timelines/components/field_renderers/field_renderers'; +import { DefaultFieldRenderer } from '../../../../../timelines/components/field_renderers/default_renderer'; import type { FlowTarget } from '../../../../../../common/search_strategy'; interface PointToolTipContentProps { diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/add_note.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/add_note.test.tsx index 980cb97d6edae..c1929be9325a8 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/add_note.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/add_note.test.tsx @@ -16,11 +16,12 @@ import { ATTACH_TO_TIMELINE_CHECKBOX_TEST_ID, } from './test_ids'; import { ReqStatus } from '../../../../notes/store/notes.slice'; -import { useIsTimelineFlyoutOpen } from '../../shared/hooks/use_is_timeline_flyout_open'; import { TimelineId } from '../../../../../common/types'; import userEvent from '@testing-library/user-event'; +import { useWhichFlyout } from '../../shared/hooks/use_which_flyout'; +import { Flyouts } from '../../shared/constants/flyouts'; -jest.mock('../../shared/hooks/use_is_timeline_flyout_open'); +jest.mock('../../shared/hooks/use_which_flyout'); const mockAddError = jest.fn(); jest.mock('../../../../common/hooks/use_app_toasts', () => ({ @@ -124,7 +125,7 @@ describe('AddNote', () => { }); it('should disable attach to timeline checkbox if flyout is not open from timeline', () => { - (useIsTimelineFlyoutOpen as jest.Mock).mockReturnValue(false); + (useWhichFlyout as jest.Mock).mockReturnValue(Flyouts.securitySolution); const { getByTestId } = renderAddNote(); @@ -132,7 +133,7 @@ describe('AddNote', () => { }); it('should disable attach to timeline checkbox if active timeline is not saved', () => { - (useIsTimelineFlyoutOpen as jest.Mock).mockReturnValue(true); + (useWhichFlyout as jest.Mock).mockReturnValue(Flyouts.timeline); const store = createMockStore({ ...mockGlobalState, @@ -157,7 +158,7 @@ describe('AddNote', () => { }); it('should have attach to timeline checkbox enabled', () => { - (useIsTimelineFlyoutOpen as jest.Mock).mockReturnValue(true); + (useWhichFlyout as jest.Mock).mockReturnValue(Flyouts.timeline); const store = createMockStore({ ...mockGlobalState, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/add_note.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/add_note.tsx index 6eea833420cb5..88c77b5d09160 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/add_note.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/add_note.tsx @@ -20,10 +20,11 @@ import { import { css } from '@emotion/react'; import { useDispatch, useSelector } from 'react-redux'; import { i18n } from '@kbn/i18n'; +import { useWhichFlyout } from '../../shared/hooks/use_which_flyout'; +import { Flyouts } from '../../shared/constants/flyouts'; import { useKibana } from '../../../../common/lib/kibana'; import { TimelineId } from '../../../../../common/types'; import { timelineSelectors } from '../../../../timelines/store'; -import { useIsTimelineFlyoutOpen } from '../../shared/hooks/use_is_timeline_flyout_open'; import { ADD_NOTE_BUTTON_TEST_ID, ADD_NOTE_MARKDOWN_TEST_ID, @@ -92,8 +93,9 @@ export const AddNote = memo(({ eventId }: AddNewNoteProps) => { ); // if the flyout is open from a timeline and that timeline is saved, we automatically check the checkbox to associate the note to it - const isTimelineFlyout = useIsTimelineFlyoutOpen(); - const [checked, setChecked] = useState(isTimelineFlyout && activeTimeline.savedObjectId != null); + const isTimelineFlyout = useWhichFlyout() === Flyouts.timeline; + + const [checked, setChecked] = useState(true); const onCheckboxChange = useCallback( (e: React.ChangeEvent) => setChecked(e.target.checked), [] @@ -132,6 +134,11 @@ export const AddNote = memo(({ eventId }: AddNewNoteProps) => { [editorValue, isMarkdownInvalid] ); + const initialCheckboxChecked = useMemo( + () => isTimelineFlyout && activeTimeline.savedObjectId != null, + [activeTimeline?.savedObjectId, isTimelineFlyout] + ); + const checkBoxDisabled = useMemo( () => !isTimelineFlyout || (isTimelineFlyout && activeTimeline?.savedObjectId == null), [activeTimeline?.savedObjectId, isTimelineFlyout] @@ -171,7 +178,7 @@ export const AddNote = memo(({ eventId }: AddNewNoteProps) => { } disabled={checkBoxDisabled} - checked={checked} + checked={initialCheckboxChecked && checked} onChange={(e) => onCheckboxChange(e)} /> diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/correlations_details_alerts_table.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/correlations_details_alerts_table.test.tsx index fec6a1efaa08f..ebea2481ab829 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/correlations_details_alerts_table.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/correlations_details_alerts_table.test.tsx @@ -11,7 +11,6 @@ import { TestProviders } from '../../../../common/mock'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import { CorrelationsDetailsAlertsTable } from './correlations_details_alerts_table'; import { usePaginatedAlerts } from '../hooks/use_paginated_alerts'; -import { CORRELATIONS_DETAILS_ALERT_PREVIEW_BUTTON_TEST_ID } from './test_ids'; import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { mockFlyoutApi } from '../../shared/mocks/mock_flyout_context'; import { mockContextValue } from '../../shared/mocks/mock_context'; @@ -94,9 +93,7 @@ describe('CorrelationsDetailsAlertsTable', () => { expect(getByTestId(`${TEST_ID}InvestigateInTimeline`)).toBeInTheDocument(); expect(getByTestId(`${TEST_ID}Table`)).toBeInTheDocument(); - expect( - queryByTestId(CORRELATIONS_DETAILS_ALERT_PREVIEW_BUTTON_TEST_ID) - ).not.toBeInTheDocument(); + expect(queryByTestId(`${TEST_ID}AlertPreviewButton`)).not.toBeInTheDocument(); expect(jest.mocked(usePaginatedAlerts)).toHaveBeenCalled(); @@ -116,9 +113,9 @@ describe('CorrelationsDetailsAlertsTable', () => { }); expect(getByTestId(`${TEST_ID}InvestigateInTimeline`)).toBeInTheDocument(); - expect(getAllByTestId(CORRELATIONS_DETAILS_ALERT_PREVIEW_BUTTON_TEST_ID).length).toBe(2); + expect(getAllByTestId(`${TEST_ID}AlertPreviewButton`).length).toBe(2); - getAllByTestId(CORRELATIONS_DETAILS_ALERT_PREVIEW_BUTTON_TEST_ID)[0].click(); + getAllByTestId(`${TEST_ID}AlertPreviewButton`)[0].click(); expect(mockFlyoutApi.openPreviewPanel).toHaveBeenCalledWith({ id: DocumentDetailsPreviewPanelKey, params: { diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/correlations_details_alerts_table.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/correlations_details_alerts_table.tsx index 5253aa1cd272b..cf55e02d9d478 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/correlations_details_alerts_table.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/correlations_details_alerts_table.tsx @@ -15,7 +15,6 @@ import { ALERT_REASON, ALERT_RULE_NAME } from '@kbn/rule-data-utils'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; -import { CORRELATIONS_DETAILS_ALERT_PREVIEW_BUTTON_TEST_ID } from './test_ids'; import { CellTooltipWrapper } from '../../shared/components/cell_tooltip_wrapper'; import type { DataProvider } from '../../../../../common/types'; import { SeverityBadge } from '../../../../common/components/severity_badge'; @@ -133,7 +132,7 @@ export const CorrelationsDetailsAlertsTable: FC ), @@ -210,7 +209,7 @@ export const CorrelationsDetailsAlertsTable: FC', () => { storage: storageMock, }, }); - (useIsTimelineFlyoutOpen as jest.Mock).mockReturnValue(false); + (useWhichFlyout as jest.Mock).mockReturnValue(Flyouts.securitySolution); storageMock.clear(); }); @@ -105,7 +106,7 @@ describe('', () => { }); it('should not render left panel tour for flyout in timeline', () => { - (useIsTimelineFlyoutOpen as jest.Mock).mockReturnValue(true); + (useWhichFlyout as jest.Mock).mockReturnValue(Flyouts.timeline); storageMock.set('securitySolution.documentDetails.newFeaturesTour.v8.14', { currentTourStep: 3, isTourActive: true, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/tour.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/tour.tsx index 4e3adc140a8aa..c1bafab10d9a7 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/tour.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/tour.tsx @@ -6,12 +6,13 @@ */ import React, { memo, useMemo } from 'react'; +import { useWhichFlyout } from '../../shared/hooks/use_which_flyout'; import { getField } from '../../shared/utils'; import { EventKind } from '../../shared/constants/event_kinds'; import { useDocumentDetailsContext } from '../../shared/context'; import { FlyoutTour } from '../../shared/components/flyout_tour'; import { getLeftSectionTourSteps } from '../../shared/utils/tour_step_config'; -import { useIsTimelineFlyoutOpen } from '../../shared/hooks/use_is_timeline_flyout_open'; +import { Flyouts } from '../../shared/constants/flyouts'; /** * Guided tour for the left panel in details flyout @@ -20,7 +21,7 @@ export const LeftPanelTour = memo(() => { const { getFieldsData, isPreview } = useDocumentDetailsContext(); const eventKind = getField(getFieldsData('event.kind')); const isAlert = eventKind === EventKind.signal; - const isTimelineFlyoutOpen = useIsTimelineFlyoutOpen(); + const isTimelineFlyoutOpen = useWhichFlyout() === Flyouts.timeline; const showTour = isAlert && !isPreview && !isTimelineFlyoutOpen; const tourStepContent = useMemo(() => getLeftSectionTourSteps(), []); 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 5fea7c0fc1126..8c7a9ab894250 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 @@ -34,7 +34,7 @@ import { InspectButton, InspectButtonContainer } from '../../../../common/compon import { NetworkDetailsLink } from '../../../../common/components/links'; import { RiskScoreEntity } from '../../../../../common/search_strategy'; import { RiskScoreLevel } from '../../../../entity_analytics/components/severity/common'; -import { DefaultFieldRenderer } from '../../../../timelines/components/field_renderers/field_renderers'; +import { DefaultFieldRenderer } from '../../../../timelines/components/field_renderers/default_renderer'; import { CellActions } from './cell_actions'; import { InputsModelId } from '../../../../common/store/inputs/constants'; import { useGlobalTime } from '../../../../common/containers/use_global_time'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/tour.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/tour.test.tsx index f0cc3f1da8559..20540184156b9 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/tour.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/tour.test.tsx @@ -18,13 +18,14 @@ import { import { useKibana as mockUseKibana } from '../../../../common/lib/kibana/__mocks__'; import { useKibana } from '../../../../common/lib/kibana'; import { FLYOUT_TOUR_CONFIG_ANCHORS } from '../../shared/utils/tour_step_config'; -import { useIsTimelineFlyoutOpen } from '../../shared/hooks/use_is_timeline_flyout_open'; import { FLYOUT_TOUR_TEST_ID } from '../../shared/components/test_ids'; import { useTourContext } from '../../../../common/components/guided_onboarding_tour/tour'; import { casesPluginMock } from '@kbn/cases-plugin/public/mocks'; +import { useWhichFlyout } from '../../shared/hooks/use_which_flyout'; +import { Flyouts } from '../../shared/constants/flyouts'; jest.mock('../../../../common/lib/kibana'); -jest.mock('../../shared/hooks/use_is_timeline_flyout_open'); +jest.mock('../../shared/hooks/use_which_flyout'); jest.mock('../../../../common/components/guided_onboarding_tour/tour'); const mockedUseKibana = mockUseKibana(); @@ -59,7 +60,7 @@ describe('', () => { cases: mockCasesContract, }, }); - (useIsTimelineFlyoutOpen as jest.Mock).mockReturnValue(false); + (useWhichFlyout as jest.Mock).mockReturnValue(Flyouts.securitySolution); (useTourContext as jest.Mock).mockReturnValue({ isTourShown: jest.fn(() => false) }); storageMock.clear(); }); @@ -112,7 +113,7 @@ describe('', () => { }); it('should not render tour for flyout in timeline', () => { - (useIsTimelineFlyoutOpen as jest.Mock).mockReturnValue(true); + (useWhichFlyout as jest.Mock).mockReturnValue(Flyouts.timeline); const { queryByText, queryByTestId } = renderRightPanelTour({ ...mockContextValue, getFieldsData: () => '', diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/tour.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/tour.tsx index 621bf90d823c3..093a93149285c 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/tour.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/tour.tsx @@ -7,6 +7,8 @@ import React, { memo, useMemo, useCallback } from 'react'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { useWhichFlyout } from '../../shared/hooks/use_which_flyout'; +import { Flyouts } from '../../shared/constants/flyouts'; import { useDocumentDetailsContext } from '../../shared/context'; import { FlyoutTour } from '../../shared/components/flyout_tour'; import { @@ -19,7 +21,6 @@ import { DocumentDetailsRightPanelKey, } from '../../shared/constants/panel_keys'; import { EventKind } from '../../shared/constants/event_kinds'; -import { useIsTimelineFlyoutOpen } from '../../shared/hooks/use_is_timeline_flyout_open'; import { useTourContext } from '../../../../common/components/guided_onboarding_tour/tour'; import { SecurityStepId } from '../../../../common/components/guided_onboarding_tour/tour_config'; import { useKibana } from '../../../../common/lib/kibana'; @@ -39,7 +40,7 @@ export const RightPanelTour = memo(() => { const eventKind = getField(getFieldsData('event.kind')); const isAlert = eventKind === EventKind.signal; - const isTimelineFlyoutOpen = useIsTimelineFlyoutOpen(); + const isTimelineFlyoutOpen = useWhichFlyout() === Flyouts.timeline; const showTour = isAlert && !isPreview && diff --git a/x-pack/test/security_solution_api_integration/test_suites/genai/invoke_ai/utils/space_test_utils.ts b/x-pack/plugins/security_solution/public/flyout/document_details/shared/constants/flyouts.ts similarity index 69% rename from x-pack/test/security_solution_api_integration/test_suites/genai/invoke_ai/utils/space_test_utils.ts rename to x-pack/plugins/security_solution/public/flyout/document_details/shared/constants/flyouts.ts index 6ffbdc492aee4..c19df7479fc1e 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/genai/invoke_ai/utils/space_test_utils.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/constants/flyouts.ts @@ -5,6 +5,7 @@ * 2.0. */ -export function getUrlPrefix(spaceId: string) { - return spaceId && spaceId !== 'default' ? `/s/${spaceId}` : ``; +export enum Flyouts { + securitySolution = 'SecuritySolution', + timeline = 'Timeline', } diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_is_timeline_flyout_open.test.ts b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_is_timeline_flyout_open.test.ts deleted file mode 100644 index 295c7256b7adb..0000000000000 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_is_timeline_flyout_open.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { renderHook } from '@testing-library/react-hooks'; -import { useIsTimelineFlyoutOpen } from './use_is_timeline_flyout_open'; - -describe('useInvestigationGuide', () => { - beforeAll(() => { - Object.defineProperty(window, 'location', { - value: { - search: '?', - }, - }); - }); - - it('should return false when timeline flyout is not in url', () => { - window.location.search = 'http://app/security/alerts'; - const hookResult = renderHook(() => useIsTimelineFlyoutOpen()); - expect(hookResult.result.current).toEqual(false); - }); - - it('should return false when timeline flyout is in url but params are empty', () => { - window.location.search = - 'http://app/security/alerts&flyout=(right:(id:document-details-right))&timelineFlyout=()'; - const hookResult = renderHook(() => useIsTimelineFlyoutOpen()); - expect(hookResult.result.current).toEqual(false); - }); - - it('should return true when timeline flyout is open', () => { - window.location.search = - 'http://app/security/alerts&flyout=(right:(id:document-details-right))&timelineFlyout=(right:(id:document-details-right,params:(id:id,indexName:index,scopeId:scope)))'; - const hookResult = renderHook(() => useIsTimelineFlyoutOpen()); - expect(hookResult.result.current).toEqual(true); - }); -}); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_is_timeline_flyout_open.ts b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_is_timeline_flyout_open.ts deleted file mode 100644 index 06599dbb356b7..0000000000000 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_is_timeline_flyout_open.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { URL_PARAM_KEY } from '../../../../common/hooks/use_url_state'; - -/** - * Hook that returns which flyout is the user currently interacting with. - * If the url contains timelineFlyout parameter and its value is not empty, we know the timeline flyout is rendered. - * As it is always on top of the normal flyout, we can deduce which flyout the user is interacting with. - */ -export const useIsTimelineFlyoutOpen = (): boolean => { - const query = new URLSearchParams(window.location.search); - return ( - query.has(URL_PARAM_KEY.timelineFlyout) && query.get(URL_PARAM_KEY.timelineFlyout) !== '()' - ); -}; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_which_flyout.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_which_flyout.test.tsx new file mode 100644 index 0000000000000..76277b8da889b --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_which_flyout.test.tsx @@ -0,0 +1,123 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { RenderHookResult } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react-hooks'; +import { useWhichFlyout } from './use_which_flyout'; +import { Flyouts } from '../constants/flyouts'; + +describe('useWhichFlyout', () => { + let hookResult: RenderHookResult<{}, string | null>; + + beforeEach(() => { + jest.clearAllMocks(); + window.location.search = '?'; + }); + + describe('no flyout open', () => { + it('should return null if only none are the url', () => { + Object.defineProperty(window, 'location', { + value: { + search: '', + }, + }); + + hookResult = renderHook(() => useWhichFlyout()); + + expect(hookResult.result.current).toEqual(null); + }); + + it('should return null if only they are the url but empty', () => { + Object.defineProperty(window, 'location', { + value: { + search: '?flyout=()&timelineFlyout=()', + }, + }); + + hookResult = renderHook(() => useWhichFlyout()); + + expect(hookResult.result.current).toEqual(null); + }); + + it('should return null if only they are the url but params are empty preview', () => { + Object.defineProperty(window, 'location', { + value: { + search: '?flyout=(preview:!())&timelineFlyout=(preview:!())', + }, + }); + + hookResult = renderHook(() => useWhichFlyout()); + + expect(hookResult.result.current).toEqual(null); + }); + }); + + describe('SecuritySolution flyout open', () => { + it('should return SecuritySolution flyout if timelineFlyout is not in the url', () => { + Object.defineProperty(window, 'location', { + value: { + search: + '?flyout=(right:(id:document-details-right,params:(id:id,indexName:indexName,scopeId:scopeId)))', + }, + }); + + hookResult = renderHook(() => useWhichFlyout()); + + expect(hookResult.result.current).toEqual(Flyouts.securitySolution); + }); + + it('should return SecuritySolution flyout if timelineFlyout is in the url but empty', () => { + Object.defineProperty(window, 'location', { + value: { + search: + '?flyout=(right:(id:document-details-right,params:(id:id,indexName:indexName,scopeId:scopeId)))&timelineFlyout=()', + }, + }); + + hookResult = renderHook(() => useWhichFlyout()); + + expect(hookResult.result.current).toEqual(Flyouts.securitySolution); + }); + + it('should return SecuritySolution flyout if timelineFlyout is in the url but params are empty preview', () => { + window.location.search = + 'http://app/security/alerts&flyout=(right:(id:document-details-right))&timelineFlyout=(preview:!())'; + + hookResult = renderHook(() => useWhichFlyout()); + + expect(hookResult.result.current).toEqual(Flyouts.securitySolution); + }); + }); + + describe('Timeline flyout open', () => { + it('should return Timeline flyout if flyout and timelineFlyout are in the url', () => { + Object.defineProperty(window, 'location', { + value: { + search: + '?flyout=(right:(id:document-details-right,params:(id:id,indexName:indexName,scopeId:scopeId)))&timelineFlyout=(right:(id:document-details-right,params:(id:id,indexName:indexName,scopeId:scopeId)))', + }, + }); + + hookResult = renderHook(() => useWhichFlyout()); + + expect(hookResult.result.current).toEqual(Flyouts.timeline); + }); + + it('should return Timeline flyout if only timelineFlyout is in the url', () => { + Object.defineProperty(window, 'location', { + value: { + search: + '?timelineFlyout=(right:(id:document-details-right,params:(id:id,indexName:indexName,scopeId:scopeId)))', + }, + }); + + hookResult = renderHook(() => useWhichFlyout()); + + expect(hookResult.result.current).toEqual(Flyouts.timeline); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_which_flyout.ts b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_which_flyout.ts new file mode 100644 index 0000000000000..a5bf69f88fcb1 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_which_flyout.ts @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Flyouts } from '../constants/flyouts'; +import { URL_PARAM_KEY } from '../../../../common/hooks/use_url_state'; + +/** + * Hook that returns which flyout is the user currently interacting with. + * If the url contains timelineFlyout parameter and its value is not empty, we know the timeline flyout is rendered. + * As it is always on top of the normal flyout, we can deduce which flyout the user is interacting with. + */ +export const useWhichFlyout = (): string | null => { + const query = new URLSearchParams(window.location.search); + + const queryHasSecuritySolutionFlyout = query.has(URL_PARAM_KEY.flyout); + const securitySolutionFlyoutHasValue = + query.get(URL_PARAM_KEY.flyout) !== '()' && query.get(URL_PARAM_KEY.flyout) !== '(preview:!())'; + const isSecuritySolutionFlyoutOpen = + queryHasSecuritySolutionFlyout && securitySolutionFlyoutHasValue; + + const queryHasTimelineFlyout = query.has(URL_PARAM_KEY.timelineFlyout); + const timelineFlyoutHasValue = + query.get(URL_PARAM_KEY.timelineFlyout) !== '()' && + query.get(URL_PARAM_KEY.timelineFlyout) !== '(preview:!())'; + const isTimelineFlyoutOpen = queryHasTimelineFlyout && timelineFlyoutHasValue; + + if (isSecuritySolutionFlyoutOpen && isTimelineFlyoutOpen) { + return Flyouts.timeline; + } + + if (isSecuritySolutionFlyoutOpen) { + return Flyouts.securitySolution; + } + + if (isTimelineFlyoutOpen) { + return Flyouts.timeline; + } + + return null; +}; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/entity_table/columns.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/entity_table/columns.tsx index d84e1357aaecd..df5c7517a294c 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/entity_table/columns.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/entity_table/columns.tsx @@ -9,7 +9,7 @@ import { css } from '@emotion/react'; import React from 'react'; import { euiThemeVars } from '@kbn/ui-theme'; import { FormattedMessage } from '@kbn/i18n-react'; -import { DefaultFieldRenderer } from '../../../../../timelines/components/field_renderers/field_renderers'; +import { DefaultFieldRenderer } from '../../../../../timelines/components/field_renderers/default_renderer'; import { getEmptyTagValue } from '../../../../../common/components/empty_value'; import type { BasicEntityData, EntityTableColumns } from './types'; diff --git a/x-pack/plugins/security_solution/public/flyout/index.tsx b/x-pack/plugins/security_solution/public/flyout/index.tsx index f768b71e32abc..e3f2bb8c82d8c 100644 --- a/x-pack/plugins/security_solution/public/flyout/index.tsx +++ b/x-pack/plugins/security_solution/public/flyout/index.tsx @@ -5,9 +5,12 @@ * 2.0. */ -import React, { memo } from 'react'; +import React, { memo, useCallback } from 'react'; import { ExpandableFlyout, type ExpandableFlyoutProps } from '@kbn/expandable-flyout'; import { useEuiTheme } from '@elastic/eui'; +import type { NetworkExpandableFlyoutProps } from './network_details'; +import { NetworkPanel, NetworkPanelKey } from './network_details'; +import { Flyouts } from './document_details/shared/constants/flyouts'; import { DocumentDetailsIsolateHostPanelKey, DocumentDetailsLeftPanelKey, @@ -124,30 +127,66 @@ const expandableFlyoutDocumentsPanels: ExpandableFlyoutProps['registeredPanels'] ), }, + { + key: NetworkPanelKey, + component: (props) => , + }, ]; +export const SECURITY_SOLUTION_ON_CLOSE_EVENT = `expandable-flyout-on-close-${Flyouts.securitySolution}`; +export const TIMELINE_ON_CLOSE_EVENT = `expandable-flyout-on-close-${Flyouts.timeline}`; + /** * Flyout used for the Security Solution application * We keep the default EUI 1000 z-index to ensure it is always rendered behind Timeline (which has a z-index of 1001) + * We propagate the onClose callback to the rest of Security Solution using a window event 'expandable-flyout-on-close-SecuritySolution' */ -export const SecuritySolutionFlyout = memo(() => ( - -)); +export const SecuritySolutionFlyout = memo(() => { + const onClose = useCallback( + () => + window.dispatchEvent( + new CustomEvent(SECURITY_SOLUTION_ON_CLOSE_EVENT, { + detail: Flyouts.securitySolution, + }) + ), + [] + ); + + return ( + + ); +}); SecuritySolutionFlyout.displayName = 'SecuritySolutionFlyout'; /** * Flyout used in Timeline * We set the z-index to 1002 to ensure it is always rendered above Timeline (which has a z-index of 1001) + * We propagate the onClose callback to the rest of Security Solution using a window event 'expandable-flyout-on-close-Timeline' */ export const TimelineFlyout = memo(() => { const { euiTheme } = useEuiTheme(); + const onClose = useCallback( + () => + window.dispatchEvent( + new CustomEvent(TIMELINE_ON_CLOSE_EVENT, { + detail: Flyouts.timeline, + }) + ), + [] + ); + return ( ); }); diff --git a/x-pack/plugins/security_solution/public/flyout/network_details/components/network_details.tsx b/x-pack/plugins/security_solution/public/flyout/network_details/components/network_details.tsx new file mode 100644 index 0000000000000..dff9a7a42191e --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/network_details/components/network_details.tsx @@ -0,0 +1,127 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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, useMemo } from 'react'; +import { useDispatch } from 'react-redux'; +import { getEsQueryConfig } from '@kbn/data-plugin/common'; +import { InputsModelId } from '../../../common/store/inputs/constants'; +import { useInvalidFilterQuery } from '../../../common/hooks/use_invalid_filter_query'; +import type { FlowTargetSourceDest } from '../../../../common/search_strategy'; +import { IpOverview } from '../../../explore/network/components/details'; +import { useDeepEqualSelector } from '../../../common/hooks/use_selector'; +import { useGlobalTime } from '../../../common/containers/use_global_time'; +import { networkToCriteria } from '../../../common/components/ml/criteria/network_to_criteria'; +import { scoreIntervalToDateTime } from '../../../common/components/ml/score/score_interval_to_datetime'; +import { useKibana } from '../../../common/lib/kibana'; +import { convertToBuildEsQuery } from '../../../common/lib/kuery'; +import { inputsSelectors } from '../../../common/store'; +import { setAbsoluteRangeDatePicker } from '../../../common/store/inputs/actions'; +import { useSourcererDataView } from '../../../sourcerer/containers'; +import { useNetworkDetails } from '../../../explore/network/containers/details'; +import { networkModel } from '../../../explore/network/store'; +import { useAnomaliesTableData } from '../../../common/components/ml/anomaly/use_anomalies_table_data'; +import { useInstalledSecurityJobNameById } from '../../../common/components/ml/hooks/use_installed_security_jobs'; +import { EmptyPrompt } from '../../../common/components/empty_prompt'; + +export interface NetworkDetailsProps { + /** + * IP value + */ + ip: string; + /** + * Destination or source information + */ + flowTarget: FlowTargetSourceDest; +} + +/** + * Component rendering all the network details for the expandable flyout + */ +export const NetworkDetails = ({ + ip, + flowTarget, + isDraggable, +}: NetworkDetailsProps & { isDraggable?: boolean }) => { + const dispatch = useDispatch(); + const { to, from, isInitializing } = useGlobalTime(); + const getGlobalQuerySelector = useMemo(() => inputsSelectors.globalQuerySelector(), []); + const getGlobalFiltersQuerySelector = useMemo( + () => inputsSelectors.globalFiltersQuerySelector(), + [] + ); + + const query = useDeepEqualSelector(getGlobalQuerySelector); + const filters = useDeepEqualSelector(getGlobalFiltersQuerySelector); + + const type = networkModel.NetworkType.details; + const narrowDateRange = useCallback( + (score, interval) => { + const fromTo = scoreIntervalToDateTime(score, interval); + dispatch( + setAbsoluteRangeDatePicker({ + id: InputsModelId.global, + from: fromTo.from, + to: fromTo.to, + }) + ); + }, + [dispatch] + ); + const { + services: { uiSettings }, + } = useKibana(); + + const { indicesExist, indexPattern, selectedPatterns } = useSourcererDataView(); + const [filterQuery, kqlError] = convertToBuildEsQuery({ + config: getEsQueryConfig(uiSettings), + indexPattern, + queries: [query], + filters, + }); + + const [loading, { id, networkDetails }] = useNetworkDetails({ + skip: isInitializing || filterQuery === undefined, + filterQuery, + indexNames: selectedPatterns, + ip, + }); + + useInvalidFilterQuery({ id, filterQuery, kqlError, query, startDate: from, endDate: to }); + const { jobNameById } = useInstalledSecurityJobNameById(); + const jobIds = useMemo(() => Object.keys(jobNameById), [jobNameById]); + const [isLoadingAnomaliesData, anomaliesData] = useAnomaliesTableData({ + criteriaFields: networkToCriteria(ip, flowTarget), + startDate: from, + endDate: to, + skip: isInitializing, + jobIds, + aggregationInterval: 'auto', + }); + + return indicesExist ? ( + + ) : ( + + ); +}; diff --git a/x-pack/plugins/security_solution/public/flyout/network_details/content.tsx b/x-pack/plugins/security_solution/public/flyout/network_details/content.tsx new file mode 100644 index 0000000000000..8c9aa355ed43a --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/network_details/content.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 type { FC } from 'react'; +import React, { memo } from 'react'; +import { EuiSpacer } from '@elastic/eui'; +import { NetworkDetails } from './components/network_details'; +import { FlyoutBody } from '../shared/components/flyout_body'; +import type { FlowTargetSourceDest } from '../../../common/search_strategy'; + +export interface PanelContentProps { + /** + * IP value + */ + ip: string; + /** + * Destination or source information + */ + flowTarget: FlowTargetSourceDest; +} + +/** + * Network details expandable flyout right section + */ +export const PanelContent: FC = memo(({ ip, flowTarget }: PanelContentProps) => { + return ( + + + + + ); +}); + +PanelContent.displayName = 'PanelContent'; diff --git a/x-pack/plugins/security_solution/public/flyout/network_details/header.tsx b/x-pack/plugins/security_solution/public/flyout/network_details/header.tsx new file mode 100644 index 0000000000000..8ffceb345b1e0 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/network_details/header.tsx @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FC } from 'react'; +import React, { memo, useMemo } from 'react'; +import type { EuiFlyoutHeader } from '@elastic/eui'; +import { SecurityPageName } from '@kbn/deeplinks-security'; +import { getNetworkDetailsUrl } from '../../common/components/link_to'; +import { SecuritySolutionLinkAnchor } from '../../common/components/links'; +import type { FlowTargetSourceDest } from '../../../common/search_strategy'; +import { FlyoutHeader } from '../shared/components/flyout_header'; +import { FlyoutTitle } from '../shared/components/flyout_title'; +import { encodeIpv6 } from '../../common/lib/helpers'; + +export interface PanelHeaderProps extends React.ComponentProps { + /** + * IP value + */ + ip: string; + /** + * Destination or source information + */ + flowTarget: FlowTargetSourceDest; +} + +/** + * + */ +export const PanelHeader: FC = memo( + ({ ip, flowTarget, ...flyoutHeaderProps }: PanelHeaderProps) => { + const href = useMemo( + () => getNetworkDetailsUrl(encodeURIComponent(encodeIpv6(ip)), flowTarget), + [flowTarget, ip] + ); + + return ( + + + + + + ); + } +); + +PanelHeader.displayName = 'PanelHeader'; diff --git a/x-pack/plugins/security_solution/public/flyout/network_details/index.tsx b/x-pack/plugins/security_solution/public/flyout/network_details/index.tsx new file mode 100644 index 0000000000000..59985e98d561f --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/network_details/index.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, { memo } from 'react'; +import type { FlyoutPanelProps } from '@kbn/expandable-flyout'; +import type { FlowTargetSourceDest } from '../../../common/search_strategy'; +import { PanelHeader } from './header'; +import { PanelContent } from './content'; + +export interface NetworkExpandableFlyoutProps extends FlyoutPanelProps { + key: 'network-details'; + params: NetworkPanelProps; +} + +export const NetworkPanelKey: NetworkExpandableFlyoutProps['key'] = 'network-details'; + +export interface NetworkPanelProps extends Record { + /** + * IP value + */ + ip: string; + /** + * Destination or source information + */ + flowTarget: FlowTargetSourceDest; +} + +/** + * Panel to be displayed in the network details expandable flyout right section + */ +export const NetworkPanel = memo(({ ip, flowTarget }: NetworkPanelProps) => { + return ( + <> + + + + ); +}); + +NetworkPanel.displayName = 'NetworkPanel'; diff --git a/x-pack/plugins/security_solution/public/flyout/shared/hooks/use_on_expandable_flyout_close.test.tsx b/x-pack/plugins/security_solution/public/flyout/shared/hooks/use_on_expandable_flyout_close.test.tsx new file mode 100644 index 0000000000000..308c1bcfc6cfc --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/shared/hooks/use_on_expandable_flyout_close.test.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 { renderHook } from '@testing-library/react-hooks'; +import { useWhichFlyout } from '../../document_details/shared/hooks/use_which_flyout'; +import { useOnExpandableFlyoutClose } from './use_on_expandable_flyout_close'; +import { Flyouts } from '../../document_details/shared/constants/flyouts'; +import { TIMELINE_ON_CLOSE_EVENT } from '../..'; + +jest.mock('../../document_details/shared/hooks/use_which_flyout'); + +describe('useOnExpandableFlyoutClose', () => { + const callbackFct = jest.fn().mockImplementation((id: string) => {}); + + it('should run the callback function and remove the event listener from the window', () => { + (useWhichFlyout as jest.Mock).mockReturnValue(Flyouts.timeline); + + window.removeEventListener = jest.fn().mockImplementationOnce((event, callback) => {}); + + renderHook(() => useOnExpandableFlyoutClose({ callback: callbackFct })); + + window.dispatchEvent( + new CustomEvent(TIMELINE_ON_CLOSE_EVENT, { + detail: Flyouts.timeline, + }) + ); + + expect(callbackFct).toHaveBeenCalledWith(Flyouts.timeline); + expect(window.removeEventListener).toBeCalled(); + }); + + it('should add event listener to window', async () => { + (useWhichFlyout as jest.Mock).mockReturnValue(Flyouts.securitySolution); + + window.addEventListener = jest.fn().mockImplementationOnce((event, callback) => {}); + + renderHook(() => useOnExpandableFlyoutClose({ callback: callbackFct })); + + expect(window.addEventListener).toBeCalled(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/flyout/shared/hooks/use_on_expandable_flyout_close.ts b/x-pack/plugins/security_solution/public/flyout/shared/hooks/use_on_expandable_flyout_close.ts new file mode 100644 index 0000000000000..e763bb222bc7a --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/shared/hooks/use_on_expandable_flyout_close.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 { useCallback, useEffect } from 'react'; +import { useWhichFlyout } from '../../document_details/shared/hooks/use_which_flyout'; +import { Flyouts } from '../../document_details/shared/constants/flyouts'; +import { SECURITY_SOLUTION_ON_CLOSE_EVENT, TIMELINE_ON_CLOSE_EVENT } from '../..'; + +export interface UseOnCloseParams { + /** + * Function to call when the event is dispatched + */ + callback: (id: string) => void; +} + +/** + * Hook to abstract the logic of listening to the onClose event for the Security Solution application. + * The kbn-expandable-flyout package provides the onClose callback, but has there are only 2 instances of the expandable flyout in Security Solution (normal and timeline) + * we need a way to propagate the onClose event to all other components. + * 2 event names are available, we pick the correct one depending on which flyout is open (if the timeline flyout is open, it is always on top, so we choose that one). + */ +export const useOnExpandableFlyoutClose = ({ callback }: UseOnCloseParams): void => { + const flyout = useWhichFlyout(); + + const eventName = + flyout === Flyouts.securitySolution + ? SECURITY_SOLUTION_ON_CLOSE_EVENT + : TIMELINE_ON_CLOSE_EVENT; + + const eventHandler = useCallback((e: CustomEventInit) => callback(e.detail), [callback]); + + useEffect(() => { + window.addEventListener(eventName, eventHandler); + + return () => window.removeEventListener(eventName, eventHandler); + }, [eventHandler, eventName]); +}; diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/get_processes_action.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/get_processes_action.tsx index 81d408e229bbd..387aed4af9060 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/get_processes_action.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/get_processes_action.tsx @@ -45,17 +45,19 @@ const StyledEuiBasicTable = styled(EuiBasicTable)` export const GetProcessesActionResult = memo( ({ command, setStore, store, status, setStatus, ResultComponent }) => { - const endpointId = command.commandDefinition?.meta?.endpointId; + const { endpointId, agentType } = command.commandDefinition?.meta ?? {}; + const comment = command.args.args?.comment?.[0]; const actionCreator = useSendGetEndpointProcessesRequest(); const actionRequestBody = useMemo(() => { return endpointId ? { endpoint_ids: [endpointId], - comment: command.args.args?.comment?.[0], + comment, + agent_type: agentType, } : undefined; - }, [endpointId, command.args.args?.comment]); + }, [endpointId, comment, agentType]); const { result, actionDetails: completedActionDetails } = useConsoleActionSubmitter< ProcessesRequestBody, diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/get_processes_action.test.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/get_processes_action.test.tsx index 08c9ffd673f5d..423d0833e6078 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/get_processes_action.test.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/get_processes_action.test.tsx @@ -14,49 +14,59 @@ import { import React from 'react'; import { getEndpointConsoleCommands } from '../../lib/console_commands_definition'; import { responseActionsHttpMocks } from '../../../../mocks/response_actions_http_mocks'; -import { enterConsoleCommand } from '../../../console/mocks'; +import { enterConsoleCommand, getConsoleSelectorsAndActionMock } from '../../../console/mocks'; import { waitFor } from '@testing-library/react'; import { getEndpointAuthzInitialState } from '../../../../../../common/endpoint/service/authz'; -import type { EndpointCapabilities } from '../../../../../../common/endpoint/service/response_actions/constants'; +import type { + EndpointCapabilities, + ResponseActionAgentType, +} from '../../../../../../common/endpoint/service/response_actions/constants'; import { ENDPOINT_CAPABILITIES } from '../../../../../../common/endpoint/service/response_actions/constants'; import { UPGRADE_AGENT_FOR_RESPONDER } from '../../../../../common/translations'; - -jest.mock('../../../../../common/experimental_features_service'); +import type { CommandDefinition } from '../../../console'; describe('When using processes action from response actions console', () => { - let render: ( - capabilities?: EndpointCapabilities[] - ) => Promise>; + let mockedContext: AppContextTestRender; + let render: () => Promise>; let renderResult: ReturnType; let apiMocks: ReturnType; let consoleManagerMockAccess: ReturnType< typeof getConsoleManagerMockRenderResultQueriesAndActions >; + let consoleSelectors: ReturnType; + let consoleCommands: CommandDefinition[]; + + const setConsoleCommands = ( + capabilities: EndpointCapabilities[] = [...ENDPOINT_CAPABILITIES], + agentType: ResponseActionAgentType = 'endpoint' + ): void => { + consoleCommands = getEndpointConsoleCommands({ + agentType, + endpointAgentId: 'a.b.c', + endpointCapabilities: capabilities, + endpointPrivileges: { + ...getEndpointAuthzInitialState(), + loading: false, + canKillProcess: true, + canSuspendProcess: true, + canGetRunningProcesses: true, + }, + }); + }; beforeEach(() => { - const mockedContext = createAppRootMockRenderer(); - + mockedContext = createAppRootMockRenderer(); apiMocks = responseActionsHttpMocks(mockedContext.coreStart.http); + setConsoleCommands(); - render = async (capabilities: EndpointCapabilities[] = [...ENDPOINT_CAPABILITIES]) => { + render = async () => { renderResult = mockedContext.render( { return { consoleProps: { 'data-test-subj': 'test', - commands: getEndpointConsoleCommands({ - agentType: 'endpoint', - endpointAgentId: 'a.b.c', - endpointCapabilities: [...capabilities], - endpointPrivileges: { - ...getEndpointAuthzInitialState(), - loading: false, - canKillProcess: true, - canSuspendProcess: true, - canGetRunningProcesses: true, - }, - }), + commands: consoleCommands, }, }; }} @@ -67,13 +77,15 @@ describe('When using processes action from response actions console', () => { await consoleManagerMockAccess.clickOnRegisterNewConsole(); await consoleManagerMockAccess.openRunningConsole(); + consoleSelectors = getConsoleSelectorsAndActionMock(renderResult); return renderResult; }; }); it('should show an error if the `running_processes` capability is not present in the endpoint', async () => { - await render([]); + setConsoleCommands([]); + await render(); enterConsoleCommand(renderResult, 'processes'); expect(renderResult.getByTestId('test-validationError-message').textContent).toEqual( @@ -228,4 +240,80 @@ describe('When using processes action from response actions console', () => { expect(apiMocks.responseProvider.actionDetails).toHaveBeenCalledTimes(1); }); }); + + describe('and when agent type is SentinelOne', () => { + beforeEach(() => { + mockedContext.setExperimentalFlag({ responseActionsSentinelOneProcessesEnabled: true }); + setConsoleCommands([], 'sentinel_one'); + }); + + it('should display processes command --help', async () => { + await render(); + enterConsoleCommand(renderResult, 'processes --help'); + + await waitFor(() => { + expect(renderResult.getByTestId('test-helpOutput').textContent).toEqual( + 'About' + + 'Show all running processes' + + 'Usage' + + 'processes [--comment]' + + 'Example' + + 'processes --comment "get the processes"' + + 'Optional parameters' + + '--comment - A comment to go along with the action' + ); + }); + }); + + it('should display correct entry in help panel', async () => { + await render(); + consoleSelectors.openHelpPanel(); + + expect( + renderResult.getByTestId('test-commandList-Responseactions-processes') + ).toHaveTextContent('processesShow all running processes'); + }); + + it('should call the api with agentType of SentinelOne', async () => { + await render(); + enterConsoleCommand(renderResult, 'processes'); + + await waitFor(() => { + expect(apiMocks.responseProvider.processes).toHaveBeenCalledWith({ + body: '{"endpoint_ids":["a.b.c"],"agent_type":"sentinel_one"}', + path: '/api/endpoint/action/running_procs', + version: '2023-10-31', + }); + }); + }); + + describe('and `responseActionsSentinelOneProcessesEnabled` feature flag is disabled', () => { + beforeEach(() => { + mockedContext.setExperimentalFlag({ responseActionsSentinelOneProcessesEnabled: false }); + setConsoleCommands([], 'sentinel_one'); + }); + + it('should not display `processes` command in console help', async () => { + await render(); + consoleSelectors.openHelpPanel(); + + expect(renderResult.queryByTestId('test-commandList-Responseactions-processes')).toBeNull(); + }); + + it('should error if user enters `process` command', async () => { + await render(); + enterConsoleCommand(renderResult, 'processes'); + + await waitFor(() => { + expect(renderResult.getByTestId('test-validationError')).toHaveTextContent( + 'Unsupported actionSupport for processes is not currently available for SentinelOne.' + ); + }); + + await waitFor(() => { + expect(apiMocks.responseProvider.processes).not.toHaveBeenCalled(); + }); + }); + }); + }); }); diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/console_commands_definition.ts b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/console_commands_definition.ts index 80dce9de15435..74c43fb535f5f 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/console_commands_definition.ts +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/console_commands_definition.ts @@ -551,6 +551,7 @@ const adjustCommandsForSentinelOne = ({ }): CommandDefinition[] => { const featureFlags = ExperimentalFeaturesService.get(); const isKillProcessEnabled = featureFlags.responseActionsSentinelOneKillProcessEnabled; + const isProcessesEnabled = featureFlags.responseActionsSentinelOneProcessesEnabled; return commandList.map((command) => { // Kill-Process: adjust command to accept only `processName` @@ -574,6 +575,7 @@ const adjustCommandsForSentinelOne = ({ if ( command.name === 'status' || (command.name === 'kill-process' && !isKillProcessEnabled) || + (command.name === 'processes' && !isProcessesEnabled) || !isAgentTypeAndActionSupported( 'sentinel_one', RESPONSE_CONSOLE_COMMAND_TO_API_COMMAND_MAP[command.name as ConsoleResponseActionCommands], diff --git a/x-pack/plugins/security_solution/public/overview/components/host_overview/endpoint_overview/index.tsx b/x-pack/plugins/security_solution/public/overview/components/host_overview/endpoint_overview/index.tsx index 76b3f45d93875..787509b8f35a9 100644 --- a/x-pack/plugins/security_solution/public/overview/components/host_overview/endpoint_overview/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/host_overview/endpoint_overview/index.tsx @@ -13,7 +13,7 @@ import { AgentStatus } from '../../../../common/components/endpoint/agents/agent import { OverviewDescriptionList } from '../../../../common/components/overview_description_list'; import type { DescriptionList } from '../../../../../common/utility_types'; import { getEmptyTagValue } from '../../../../common/components/empty_value'; -import { DefaultFieldRenderer } from '../../../../timelines/components/field_renderers/field_renderers'; +import { DefaultFieldRenderer } from '../../../../timelines/components/field_renderers/default_renderer'; import * as i18n from './translations'; import type { EndpointFields } from '../../../../../common/search_strategy/security_solution/hosts'; import { HostPolicyResponseActionStatus } from '../../../../../common/search_strategy/security_solution/hosts'; diff --git a/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx b/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx index b25509c1b88f5..3dfeb6a47ae94 100644 --- a/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx @@ -19,10 +19,8 @@ import { buildHostNamesFilter, RiskScoreEntity } from '../../../../common/search import type { DescriptionList } from '../../../../common/utility_types'; import { useDarkMode } from '../../../common/lib/kibana'; import { getEmptyTagValue } from '../../../common/components/empty_value'; -import { - DefaultFieldRenderer, - hostIdRenderer, -} from '../../../timelines/components/field_renderers/field_renderers'; +import { hostIdRenderer } from '../../../timelines/components/field_renderers/field_renderers'; +import { DefaultFieldRenderer } from '../../../timelines/components/field_renderers/default_renderer'; import { FirstLastSeen, FirstLastSeenType, diff --git a/x-pack/plugins/security_solution/public/overview/components/user_overview/index.tsx b/x-pack/plugins/security_solution/public/overview/components/user_overview/index.tsx index 102e39cf1b740..3d10ad4b77e76 100644 --- a/x-pack/plugins/security_solution/public/overview/components/user_overview/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/user_overview/index.tsx @@ -18,7 +18,7 @@ import { buildUserNamesFilter, RiskScoreEntity } from '../../../../common/search import type { DescriptionList } from '../../../../common/utility_types'; import { useDarkMode } from '../../../common/lib/kibana'; import { getEmptyTagValue } from '../../../common/components/empty_value'; -import { DefaultFieldRenderer } from '../../../timelines/components/field_renderers/field_renderers'; +import { DefaultFieldRenderer } from '../../../timelines/components/field_renderers/default_renderer'; import { FirstLastSeen, FirstLastSeenType, diff --git a/x-pack/plugins/security_solution/public/timelines/components/field_renderers/__snapshots__/field_renderers.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/field_renderers/__snapshots__/field_renderers.test.tsx.snap index fd6498075112b..17ae6d1941be8 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/field_renderers/__snapshots__/field_renderers.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/timelines/components/field_renderers/__snapshots__/field_renderers.test.tsx.snap @@ -84,16 +84,6 @@ exports[`Field Renderers #autonomousSystemRenderer it renders correctly against `; -exports[`Field Renderers #dateRenderer it renders correctly against snapshot 1`] = ` - - - Feb 7, 2019 @ 17:19:41.636 - - -`; - exports[`Field Renderers #hostIdRenderer it renders correctly against snapshot 1`] = ` .c0 > span.euiToolTipAnchor { diff --git a/x-pack/plugins/security_solution/public/timelines/components/field_renderers/default_renderer/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/field_renderers/default_renderer/index.test.tsx new file mode 100644 index 0000000000000..74ce6e82615e8 --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/field_renderers/default_renderer/index.test.tsx @@ -0,0 +1,128 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { TestProviders } from '../../../../common/mock'; +import { mockGetUrlForApp } from '@kbn/security-solution-navigation/mocks/context'; +import { DefaultFieldRenderer, DefaultFieldRendererOverflow } from '.'; + +jest.mock('../../../../common/lib/kibana'); +jest.mock('@kbn/security-solution-navigation/src/context'); +mockGetUrlForApp.mockImplementation( + (appId: string, options?: { path?: string; deepLinkId?: boolean }) => + `${appId}/${options?.deepLinkId ?? ''}${options?.path ?? ''}` +); + +jest.mock('../../../../common/hooks/use_get_field_spec'); + +export const DEFAULT_MORE_MAX_HEIGHT = '200px'; + +describe('Field Renderers', () => { + describe('DefaultFieldRenderer', () => { + test('it should render a single item', () => { + render( + + + + ); + expect(screen.getByTestId('DefaultFieldRendererComponent').textContent).toEqual('item1 '); + }); + + test('it should render two items', () => { + render( + + + + ); + + expect(screen.getByTestId('DefaultFieldRendererComponent').textContent).toEqual( + 'item1,item2 ' + ); + }); + + test('it should render all items when the item count exactly equals displayCount', () => { + render( + + + + ); + + expect(screen.getByTestId('DefaultFieldRendererComponent').textContent).toEqual( + 'item1,item2,item3,item4,item5 ' + ); + }); + + test('it should render all items up to displayCount and the expected "+ n More" popover anchor text for items greater than displayCount', () => { + render( + + + + ); + expect(screen.getByTestId('DefaultFieldRendererComponent').textContent).toEqual( + 'item1,item2,item3,item4,item5 ,+2 More' + ); + }); + }); + describe('DefaultFieldRendererOverflow', () => { + const idPrefix = 'prefix-1'; + const rowItems = ['item1', 'item2', 'item3', 'item4', 'item5', 'item6', 'item7']; + + test('it should render the length of items after the overflowIndexStart', () => { + render( + + + + ); + + expect(screen.getByTestId('DefaultFieldRendererOverflow-button').textContent).toEqual( + '+2 More' + ); + expect(screen.queryByTestId('more-container')).not.toBeInTheDocument(); + }); + + test('it should render the items after overflowIndexStart in the popover', () => { + render( + + + + ); + + userEvent.click(screen.getByTestId('DefaultFieldRendererOverflow-button')); + expect(screen.getByRole('dialog')).toBeInTheDocument(); + expect(screen.getByTestId('more-container').textContent).toEqual('item6item7'); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/field_renderers/default_renderer/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/field_renderers/default_renderer/index.tsx new file mode 100644 index 0000000000000..df16f50524095 --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/field_renderers/default_renderer/index.tsx @@ -0,0 +1,166 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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, EuiButtonEmpty, EuiPopover } from '@elastic/eui'; +import React, { useCallback, useMemo, useState } from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { Spacer } from '../../../../common/components/page'; +import { DefaultDraggable } from '../../../../common/components/draggables'; +import { getEmptyTagValue } from '../../../../common/components/empty_value'; +import { escapeDataProviderId } from '../../../../common/components/drag_and_drop/helpers'; +import { MoreContainer } from '../more_container'; + +interface DefaultFieldRendererProps { + attrName: string; + displayCount?: number; + idPrefix: string; + isDraggable?: boolean; + moreMaxHeight?: string; + render?: (item: string) => React.ReactNode; + rowItems: string[] | null | undefined; + scopeId?: string; +} + +export const IpOverviewId = 'ip-overview'; + +/** The default max-height of the popover used to show "+n More" items (e.g. `+9 More`) */ +export const DEFAULT_MORE_MAX_HEIGHT = '200px'; + +export const DefaultFieldRendererComponent: React.FC = ({ + attrName, + displayCount = 1, + idPrefix, + isDraggable = false, + moreMaxHeight = DEFAULT_MORE_MAX_HEIGHT, + render, + rowItems, + scopeId, +}) => { + if (rowItems != null && rowItems.length > 0) { + const draggables = rowItems.slice(0, displayCount).map((rowItem, index) => { + const id = escapeDataProviderId( + `default-field-renderer-default-draggable-${idPrefix}-${attrName}-${rowItem}` + ); + return ( + + {index !== 0 && ( + <> + {','} + + + )} + {typeof rowItem === 'string' && ( + + {render ? render(rowItem) : rowItem} + + )} + + ); + }); + + return draggables.length > 0 ? ( + + {draggables} + + + + + ) : ( + getEmptyTagValue() + ); + } else { + return getEmptyTagValue(); + } +}; + +export const DefaultFieldRenderer = React.memo(DefaultFieldRendererComponent); + +DefaultFieldRenderer.displayName = 'DefaultFieldRenderer'; + +interface DefaultFieldRendererOverflowProps { + attrName: string; + rowItems: string[]; + idPrefix: string; + render?: (item: string) => React.ReactNode; + overflowIndexStart?: number; + moreMaxHeight: string; + scopeId?: string; +} + +export const DefaultFieldRendererOverflow = React.memo( + ({ attrName, idPrefix, moreMaxHeight, overflowIndexStart = 5, render, rowItems, scopeId }) => { + const [isOpen, setIsOpen] = useState(false); + const togglePopover = useCallback(() => setIsOpen((currentIsOpen) => !currentIsOpen), []); + const button = useMemo( + () => ( + <> + {' ,'} + + {`+${rowItems.length - overflowIndexStart} `} + + + + ), + [togglePopover, overflowIndexStart, rowItems.length] + ); + + return ( + + {rowItems.length > overflowIndexStart && ( + + + + )} + + ); + } +); + +DefaultFieldRendererOverflow.displayName = 'DefaultFieldRendererOverflow'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/field_renderers/field_renderers.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/field_renderers/field_renderers.test.tsx index c6d5c657d7790..dc867b61ecfe7 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/field_renderers/field_renderers.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/field_renderers/field_renderers.test.tsx @@ -7,22 +7,14 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; - import { TestProviders } from '../../../common/mock'; import { getEmptyValue } from '../../../common/components/empty_value'; - import { autonomousSystemRenderer, - dateRenderer, hostNameRenderer, locationRenderer, whoisRenderer, reputationRenderer, - DefaultFieldRenderer, - DEFAULT_MORE_MAX_HEIGHT, - DefaultFieldRendererOverflow, - MoreContainer, } from './field_renderers'; import { mockData } from '../../../explore/network/components/details/mock'; import type { AutonomousSystem } from '../../../../common/search_strategy'; @@ -65,21 +57,6 @@ describe('Field Renderers', () => { }); }); - describe('#dateRenderer', () => { - test('it renders correctly against snapshot', () => { - const { asFragment } = render(dateRenderer(mockData.complete.source?.firstSeen), { - wrapper: TestProviders, - }); - - expect(asFragment()).toMatchSnapshot(); - }); - - test('it renders emptyTagValue when invalid field provided', () => { - render({dateRenderer(null)}); - expect(screen.getByText(getEmptyValue())).toBeInTheDocument(); - }); - }); - describe('#autonomousSystemRenderer', () => { const emptyMock: AutonomousSystem = { organization: { name: null }, number: null }; const halfEmptyMock: AutonomousSystem = { organization: { name: 'Test Org' }, number: null }; @@ -108,17 +85,23 @@ describe('Field Renderers', () => { }); }); + const emptyIdHost: Partial = { + name: ['test'], + id: undefined, + ip: ['10.10.10.10'], + }; + const emptyIpHost: Partial = { + name: ['test'], + id: ['test'], + ip: undefined, + }; + const emptyNameHost: Partial = { + name: undefined, + id: ['test'], + ip: ['10.10.10.10'], + }; + describe('#hostIdRenderer', () => { - const emptyIdHost: Partial = { - name: ['test'], - id: undefined, - ip: ['10.10.10.10'], - }; - const emptyIpHost: Partial = { - name: ['test'], - id: ['test'], - ip: undefined, - }; test('it renders correctly against snapshot', () => { const { asFragment } = render( {hostNameRenderer(mockData.complete.host, '10.10.10.10')} @@ -144,21 +127,6 @@ describe('Field Renderers', () => { }); describe('#hostNameRenderer', () => { - const emptyIdHost: Partial = { - name: ['test'], - id: undefined, - ip: ['10.10.10.10'], - }; - const emptyIpHost: Partial = { - name: ['test'], - id: ['test'], - ip: undefined, - }; - const emptyNameHost: Partial = { - name: undefined, - id: ['test'], - ip: ['10.10.10.10'], - }; test('it renders correctly against snapshot', () => { const { asFragment } = render( {hostNameRenderer(mockData.complete.host, '10.10.10.10')} @@ -205,222 +173,4 @@ describe('Field Renderers', () => { expect(asFragment()).toMatchSnapshot(); }); }); - - describe('DefaultFieldRenderer', () => { - test('it should render a single item', () => { - render( - - - - ); - expect(screen.getByTestId('DefaultFieldRendererComponent').textContent).toEqual('item1 '); - }); - - test('it should render two items', () => { - render( - - - - ); - - expect(screen.getByTestId('DefaultFieldRendererComponent').textContent).toEqual( - 'item1,item2 ' - ); - }); - - test('it should render all items when the item count exactly equals displayCount', () => { - render( - - - - ); - - expect(screen.getByTestId('DefaultFieldRendererComponent').textContent).toEqual( - 'item1,item2,item3,item4,item5 ' - ); - }); - - test('it should render all items up to displayCount and the expected "+ n More" popover anchor text for items greater than displayCount', () => { - render( - - - - ); - expect(screen.getByTestId('DefaultFieldRendererComponent').textContent).toEqual( - 'item1,item2,item3,item4,item5 ,+2 More' - ); - }); - }); - - describe('MoreContainer', () => { - const idPrefix = 'prefix-1'; - const rowItems = ['item1', 'item2', 'item3', 'item4', 'item5', 'item6', 'item7']; - - test('it should only render the items after overflowIndexStart', () => { - render( - - - - ); - - expect(screen.getByTestId('more-container').textContent).toEqual('item6item7'); - }); - - test('it should render all the items when overflowIndexStart is zero', () => { - render( - - - - ); - - expect(screen.getByTestId('more-container').textContent).toEqual( - 'item1item2item3item4item5item6item7' - ); - }); - - test('it should have the eui-yScroll to enable scrolling when necessary', () => { - render( - - - - ); - - expect(screen.getByTestId('more-container')).toHaveClass('eui-yScroll'); - }); - - test('it should use the moreMaxHeight prop as the value for the max-height style', () => { - render( - - - - ); - - expect(screen.getByTestId('more-container')).toHaveStyle( - `max-height: ${DEFAULT_MORE_MAX_HEIGHT}` - ); - }); - - test('it should render with correct attrName prop', () => { - render( - - - - ); - - screen - .getAllByTestId('cellActions-renderContent-mock.attr') - .forEach((element) => expect(element).toBeInTheDocument()); - }); - - test('it should only invoke the optional render function when provided', () => { - const renderFn = jest.fn(); - - render( - - - - ); - - expect(renderFn).toHaveBeenCalledTimes(2); - }); - }); - - describe('DefaultFieldRendererOverflow', () => { - const idPrefix = 'prefix-1'; - const rowItems = ['item1', 'item2', 'item3', 'item4', 'item5', 'item6', 'item7']; - - test('it should render the length of items after the overflowIndexStart', () => { - render( - - - - ); - - expect(screen.getByTestId('DefaultFieldRendererOverflow-button').textContent).toEqual( - '+2 More' - ); - expect(screen.queryByTestId('more-container')).not.toBeInTheDocument(); - }); - - test('it should render the items after overflowIndexStart in the popover', () => { - render( - - - - ); - - userEvent.click(screen.getByTestId('DefaultFieldRendererOverflow-button')); - - expect( - screen.getByText( - 'You are in a dialog. Press Escape, or tap/click outside the dialog to close.' - ) - ).toBeInTheDocument(); - expect(screen.getByTestId('more-container').textContent).toEqual('item6item7'); - }); - }); }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/field_renderers/field_renderers.tsx b/x-pack/plugins/security_solution/public/timelines/components/field_renderers/field_renderers.tsx index 4c3936deebc9c..1cb30270fb4f7 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/field_renderers/field_renderers.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/field_renderers/field_renderers.tsx @@ -5,44 +5,23 @@ * 2.0. */ -import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiPopover } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { getOr } from 'lodash/fp'; -import React, { useCallback, Fragment, useMemo, useState, useContext } from 'react'; -import styled from 'styled-components'; - +import React, { Fragment } from 'react'; import type { HostEcs } from '@kbn/securitysolution-ecs'; -import { getSourcererScopeId } from '../../../helpers'; -import { - SecurityCellActions, - CellActionsMode, - SecurityCellActionsTrigger, -} from '../../../common/components/cell_actions'; import type { AutonomousSystem, FlowTarget, FlowTargetSourceDest, NetworkDetailsStrategyResponse, } from '../../../../common/search_strategy'; -import { escapeDataProviderId } from '../../../common/components/drag_and_drop/helpers'; import { DefaultDraggable } from '../../../common/components/draggables'; -import { defaultToEmptyTag, getEmptyTagValue } from '../../../common/components/empty_value'; -import { FormattedRelativePreferenceDate } from '../../../common/components/formatted_date'; +import { getEmptyTagValue } from '../../../common/components/empty_value'; import { HostDetailsLink, ReputationLink, WhoIsLink } from '../../../common/components/links'; -import { Spacer } from '../../../common/components/page'; import * as i18n from '../../../explore/network/components/details/translations'; -import { SourcererScopeName } from '../../../sourcerer/store/model'; -import { TimelineContext } from '../timeline'; - -const DraggableContainerFlexGroup = styled(EuiFlexGroup)` - flex-grow: unset; -`; export const IpOverviewId = 'ip-overview'; -/** The default max-height of the popover used to show "+n More" items (e.g. `+9 More`) */ -export const DEFAULT_MORE_MAX_HEIGHT = '200px'; - export const locationRenderer = ( fieldNames: string[], data: NetworkDetailsStrategyResponse['networkDetails'], @@ -76,10 +55,6 @@ export const locationRenderer = ( getEmptyTagValue() ); -export const dateRenderer = (timestamp?: string | null): React.ReactElement => ( - -); - export const autonomousSystemRenderer = ( as: AutonomousSystem, flowTarget: FlowTarget | FlowTargetSourceDest, @@ -192,212 +167,3 @@ export const whoisRenderer = (ip: string) => {i18n.VIEW_W export const reputationRenderer = (ip: string): React.ReactElement => ( ); - -interface DefaultFieldRendererProps { - attrName: string; - displayCount?: number; - idPrefix: string; - isDraggable?: boolean; - moreMaxHeight?: string; - render?: (item: string) => React.ReactNode; - rowItems: string[] | null | undefined; - scopeId?: string; -} - -export const DefaultFieldRendererComponent: React.FC = ({ - attrName, - displayCount = 1, - idPrefix, - isDraggable = false, - moreMaxHeight = DEFAULT_MORE_MAX_HEIGHT, - render, - rowItems, - scopeId, -}) => { - if (rowItems != null && rowItems.length > 0) { - const draggables = rowItems.slice(0, displayCount).map((rowItem, index) => { - const id = escapeDataProviderId( - `default-field-renderer-default-draggable-${idPrefix}-${attrName}-${rowItem}` - ); - return ( - - {index !== 0 && ( - <> - {','} - - - )} - {typeof rowItem === 'string' && ( - - {render ? render(rowItem) : rowItem} - - )} - - ); - }); - - return draggables.length > 0 ? ( - - {draggables} - - - - - ) : ( - getEmptyTagValue() - ); - } else { - return getEmptyTagValue(); - } -}; - -export const DefaultFieldRenderer = React.memo(DefaultFieldRendererComponent); - -DefaultFieldRenderer.displayName = 'DefaultFieldRenderer'; - -interface DefaultFieldRendererOverflowProps { - attrName: string; - rowItems: string[]; - idPrefix: string; - render?: (item: string) => React.ReactNode; - overflowIndexStart?: number; - moreMaxHeight: string; - scopeId?: string; -} - -interface MoreContainerProps { - fieldName: string; - values: string[]; - idPrefix: string; - moreMaxHeight: string; - overflowIndexStart: number; - render?: (item: string) => React.ReactNode; - scopeId?: string; -} - -export const MoreContainer = React.memo( - ({ fieldName, idPrefix, moreMaxHeight, overflowIndexStart, render, values, scopeId }) => { - const { timelineId } = useContext(TimelineContext); - const defaultedScopeId = scopeId ?? timelineId; - const sourcererScopeId = getSourcererScopeId(defaultedScopeId ?? ''); - - const moreItemsWithHoverActions = useMemo( - () => - values.slice(overflowIndexStart).reduce((acc, value, index) => { - const id = escapeDataProviderId(`${idPrefix}-${fieldName}-${value}-${index}`); - - if (typeof value === 'string' && fieldName != null) { - acc.push( - - - <>{render ? render(value) : defaultToEmptyTag(value)} - - - ); - } - - return acc; - }, []), - [values, overflowIndexStart, idPrefix, fieldName, sourcererScopeId, defaultedScopeId, render] - ); - - return ( -
    - - {moreItemsWithHoverActions} - -
    - ); - } -); -MoreContainer.displayName = 'MoreContainer'; - -export const DefaultFieldRendererOverflow = React.memo( - ({ attrName, idPrefix, moreMaxHeight, overflowIndexStart = 5, render, rowItems, scopeId }) => { - const [isOpen, setIsOpen] = useState(false); - const togglePopover = useCallback(() => setIsOpen((currentIsOpen) => !currentIsOpen), []); - const button = useMemo( - () => ( - <> - {' ,'} - - {`+${rowItems.length - overflowIndexStart} `} - - - - ), - [togglePopover, overflowIndexStart, rowItems.length] - ); - - return ( - - {rowItems.length > overflowIndexStart && ( - - - - )} - - ); - } -); - -DefaultFieldRendererOverflow.displayName = 'DefaultFieldRendererOverflow'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/field_renderers/more_container/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/field_renderers/more_container/index.test.tsx new file mode 100644 index 0000000000000..11e9a6851e624 --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/field_renderers/more_container/index.test.tsx @@ -0,0 +1,130 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { TestProviders } from '../../../../common/mock'; +import { MoreContainer } from '.'; +import { mockGetUrlForApp } from '@kbn/security-solution-navigation/mocks/context'; + +jest.mock('../../../../common/lib/kibana'); +jest.mock('@kbn/security-solution-navigation/src/context'); +mockGetUrlForApp.mockImplementation( + (appId: string, options?: { path?: string; deepLinkId?: boolean }) => + `${appId}/${options?.deepLinkId ?? ''}${options?.path ?? ''}` +); + +jest.mock('../../../../common/hooks/use_get_field_spec'); + +const DEFAULT_MORE_MAX_HEIGHT = '100px'; + +describe('Field Renderers', () => { + describe('MoreContainer', () => { + const idPrefix = 'prefix-1'; + const rowItems = ['item1', 'item2', 'item3', 'item4', 'item5', 'item6', 'item7']; + + test('it should only render the items after overflowIndexStart', () => { + render( + + + + ); + + expect(screen.getByTestId('more-container').textContent).toEqual('item6item7'); + }); + + test('it should render all the items when overflowIndexStart is zero', () => { + render( + + + + ); + + expect(screen.getByTestId('more-container').textContent).toEqual( + 'item1item2item3item4item5item6item7' + ); + }); + + test('it should have the eui-yScroll to enable scrolling when necessary', () => { + render( + + + + ); + + expect(screen.getByTestId('more-container')).toHaveClass('eui-yScroll'); + }); + + test('it should use the moreMaxHeight prop as the value for the max-height style', () => { + render( + + + + ); + + expect(screen.getByTestId('more-container')).toHaveStyle( + `max-height: ${DEFAULT_MORE_MAX_HEIGHT}` + ); + }); + + test('it should render with correct attrName prop', () => { + render( + + + + ); + + screen + .getAllByTestId('cellActions-renderContent-mock.attr') + .forEach((element) => expect(element).toBeInTheDocument()); + }); + + test('it should only invoke the optional render function when provided', () => { + const renderFn = jest.fn(); + + render( + + + + ); + + expect(renderFn).toHaveBeenCalledTimes(2); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/field_renderers/more_container/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/field_renderers/more_container/index.tsx new file mode 100644 index 0000000000000..8936b77d22fb5 --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/field_renderers/more_container/index.tsx @@ -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 React, { useContext, useMemo } from 'react'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { css } from '@emotion/css'; +import classNames from 'classnames'; +import { TimelineContext } from '../../timeline'; +import { getSourcererScopeId } from '../../../../helpers'; +import { escapeDataProviderId } from '../../../../common/components/drag_and_drop/helpers'; +import { defaultToEmptyTag } from '../../../../common/components/empty_value'; +import { SourcererScopeName } from '../../../../sourcerer/store/model'; +import { + SecurityCellActions, + CellActionsMode, + SecurityCellActionsTrigger, +} from '../../../../common/components/cell_actions'; + +interface MoreContainerProps { + fieldName: string; + values: string[]; + idPrefix: string; + moreMaxHeight?: string; + overflowIndexStart: number; + render?: (item: string) => React.ReactNode; + scopeId?: string; +} +/** The default max-height of the popover used to show "+n More" items (e.g. `+9 More`) */ +export const DEFAULT_MORE_MAX_HEIGHT = '200px'; + +export const MoreContainer = React.memo( + ({ + fieldName, + idPrefix, + moreMaxHeight = DEFAULT_MORE_MAX_HEIGHT, + overflowIndexStart, + render, + values, + scopeId, + }) => { + const { timelineId } = useContext(TimelineContext); + const defaultedScopeId = scopeId ?? timelineId; + const sourcererScopeId = getSourcererScopeId(defaultedScopeId ?? ''); + + const moreItemsWithHoverActions = useMemo( + () => + values.slice(overflowIndexStart).reduce((acc, value, index) => { + const id = escapeDataProviderId(`${idPrefix}-${fieldName}-${value}-${index}`); + + if (typeof value === 'string' && fieldName != null) { + acc.push( + + + <>{render ? render(value) : defaultToEmptyTag(value)} + + + ); + } + + return acc; + }, []), + [values, overflowIndexStart, idPrefix, fieldName, sourcererScopeId, defaultedScopeId, render] + ); + + const moreContainerStyles = () => css` + max-height: ${moreMaxHeight}; + padding-right: 2px; + `; + + const moreContainerClasses = classNames(moreContainerStyles(), 'eui-yScroll'); + + return ( +
    + + {moreItemsWithHoverActions} + +
    + ); + } +); +MoreContainer.displayName = 'MoreContainer'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/formatted_ip/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/formatted_ip/index.test.tsx index 97652a97d9897..fae840426cd0b 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/formatted_ip/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/formatted_ip/index.test.tsx @@ -13,6 +13,7 @@ import { TestProviders } from '../../../common/mock'; import { TimelineId, TimelineTabs } from '../../../../common/types/timeline'; import { timelineActions } from '../../store'; import { StatefulEventContext } from '../../../common/components/events_viewer/stateful_event_context'; +import { NetworkPanelKey } from '../../../flyout/network_details'; jest.mock('react-redux', () => { const origin = jest.requireActual('react-redux'); @@ -54,6 +55,13 @@ jest.mock('../../store', () => { }; }); +const mockOpenFlyout = jest.fn(); +jest.mock('@kbn/expandable-flyout', () => ({ + useExpandableFlyoutApi: () => ({ + openFlyout: mockOpenFlyout, + }), +})); + describe('FormattedIp', () => { const props = { value: '192.168.1.1', @@ -100,7 +108,7 @@ describe('FormattedIp', () => { expect(timelineActions.toggleDetailPanel).not.toHaveBeenCalled(); }); - test('if enableIpDetailsFlyout, should open NetworkDetailsSidePanel', () => { + test('if enableIpDetailsFlyout, should open NetworkDetails expandable flyout', () => { const context = { enableHostDetailsFlyout: true, enableIpDetailsFlyout: true, @@ -116,14 +124,14 @@ describe('FormattedIp', () => { ); userEvent.click(screen.getByTestId('network-details')); - expect(timelineActions.toggleDetailPanel).toHaveBeenCalledWith({ - id: context.timelineID, - panelView: 'networkDetail', - params: { - flowTarget: 'source', - ip: props.value, + expect(mockOpenFlyout).toHaveBeenCalledWith({ + right: { + id: NetworkPanelKey, + params: { + ip: props.value, + flowTarget: 'source', + }, }, - tabType: context.tabType, }); }); }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/formatted_ip/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/formatted_ip/index.tsx index 20dcfc89452a3..50204c7ab018d 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/formatted_ip/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/formatted_ip/index.tsx @@ -7,13 +7,11 @@ import { isArray, isEmpty, isString, uniq } from 'lodash/fp'; import React, { useCallback, useMemo, useContext } from 'react'; -import { useDispatch } from 'react-redux'; import deepEqual from 'fast-deep-equal'; import type { EuiButtonEmpty, EuiButtonIcon } from '@elastic/eui'; -import type { ExpandedDetailType } from '../../../../common/types'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import { StatefulEventContext } from '../../../common/components/events_viewer/stateful_event_context'; -import { getScopedActions } from '../../../helpers'; import { FlowTargetSourceDest } from '../../../../common/search_strategy/security_solution/network'; import { DragEffects, @@ -26,8 +24,8 @@ import { parseQueryValue } from '../timeline/body/renderers/parse_query_value'; import type { DataProvider } from '../timeline/data_providers/data_provider'; import { IS_OPERATOR } from '../timeline/data_providers/data_provider'; import { Provider } from '../timeline/data_providers/provider'; -import type { TimelineTabs } from '../../../../common/types/timeline'; import { NetworkDetailsLink } from '../../../common/components/links'; +import { NetworkPanelKey } from '../../../flyout/network_details'; const getUniqueId = ({ contextId, @@ -165,6 +163,8 @@ const AddressLinksItemComponent: React.FC = ({ truncate, title, }) => { + const { openFlyout } = useExpandableFlyoutApi(); + const key = `address-links-draggable-wrapper-${getUniqueId({ contextId, eventId, @@ -177,7 +177,6 @@ const AddressLinksItemComponent: React.FC = ({ [address, contextId, eventId, fieldName] ); - const dispatch = useDispatch(); const eventContext = useContext(StatefulEventContext); const isInTimelineContext = address && eventContext?.enableIpDetailsFlyout && eventContext?.timelineID; @@ -190,29 +189,20 @@ const AddressLinksItemComponent: React.FC = ({ } if (eventContext && isInTimelineContext) { - const { tabType, timelineID } = eventContext; - const updatedExpandedDetail: ExpandedDetailType = { - panelView: 'networkDetail', - params: { - ip: address, - flowTarget: fieldName.includes(FlowTargetSourceDest.destination) - ? FlowTargetSourceDest.destination - : FlowTargetSourceDest.source, + openFlyout({ + right: { + id: NetworkPanelKey, + params: { + ip: address, + flowTarget: fieldName.includes(FlowTargetSourceDest.destination) + ? FlowTargetSourceDest.destination + : FlowTargetSourceDest.source, + }, }, - }; - const scopedActions = getScopedActions(timelineID); - if (scopedActions) { - dispatch( - scopedActions.toggleDetailPanel({ - ...updatedExpandedDetail, - id: timelineID, - tabType: tabType as TimelineTabs, - }) - ); - } + }); } }, - [onClick, eventContext, isInTimelineContext, address, fieldName, dispatch] + [onClick, eventContext, isInTimelineContext, address, fieldName, openFlyout] ); // The below is explicitly defined this way as the onClick takes precedence when it and the href are both defined 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 d745e4abaa645..d343bb1371742 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 @@ -94,7 +94,7 @@ describe('NewTimelineButton', () => { show: true, timelineType: TimelineType.template, updated: undefined, - excludedRowRendererIds: [...Object.values(RowRendererId)], + excludedRowRendererIds: [], }); }); }); 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 b31c7ba471bcf..a647c0ed44535 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 @@ -350,6 +350,7 @@ describe('helpers', () => { expect(newTimeline).toEqual({ ...defaultTimeline, columns: defaultUdtHeaders, + excludedRowRendererIds: [], }); }); @@ -500,6 +501,7 @@ describe('helpers', () => { timelineType: TimelineType.template, title: 'Awesome Timeline', columns: defaultUdtHeaders, + excludedRowRendererIds: [], }); }); 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 d31ad321b28c1..ec90e8477c72e 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 @@ -22,8 +22,13 @@ import type { PinnedEvent, Note, } from '../../../../common/api/timeline'; +import { + RowRendererId, + DataProviderType, + TimelineStatus, + TimelineType, +} from '../../../../common/api/timeline'; import { TimelineId, TimelineTabs } from '../../../../common/types/timeline'; -import { DataProviderType, TimelineStatus, TimelineType } from '../../../../common/api/timeline'; import { useUpdateTimeline } from './use_update_timeline'; import type { TimelineModel } from '../../store/model'; @@ -256,6 +261,7 @@ export const defaultTimelineToTimelineModel = ( } : timeline.dateRange, dataProviders: getDataProviders(duplicate, timeline.dataProviders, timelineType), + excludedRowRendererIds: isTemplate ? [] : Object.keys(RowRendererId), eventIdToNoteIds: setEventIdToNoteIds(duplicate, timeline.eventIdToNoteIds), filters: timeline.filters != null ? timeline.filters.map(setTimelineFilters) : [], isFavorite: duplicate @@ -358,9 +364,10 @@ export const useQueryTimelineById = () => { show: openTimeline, initialized: true, savedSearchId: savedSearchId ?? null, - excludedRowRendererIds: !unifiedComponentsInTimelineDisabled - ? timelineDefaults.excludedRowRendererIds - : [], + excludedRowRendererIds: + !unifiedComponentsInTimelineDisabled && timelineType !== TimelineType.template + ? timelineDefaults.excludedRowRendererIds + : [], }, }); resetDiscoverAppState(); diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/side_panel/__snapshots__/index.test.tsx.snap index 410b07fdc526a..0763fc3c969a6 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/__snapshots__/index.test.tsx.snap @@ -284,629 +284,3 @@ exports[`Details Panel Component DetailsPanel:EventDetails: rendering it should
    `; - -exports[`Details Panel Component DetailsPanel:HostDetails: rendering it should render the Host Details view in the Details Panel when the panelView is hostDetail and the hostName is set 1`] = ` -.c3 { - color: #98a2b3; -} - -.c2 { - word-break: break-word; -} - -.c2 dt { - font-size: 12px !important; -} - -.c2 dd { - width: -webkit-fit-content; - width: -moz-fit-content; - width: fit-content; -} - -.c2 dd > div { - width: -webkit-fit-content; - width: -moz-fit-content; - width: fit-content; -} - -.c1 { - position: relative; -} - -.c1 .euiButtonIcon { - position: absolute; - right: 12px; - top: 6px; - z-index: 2; -} - -.c0 { - width: 100%; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-flex: 1; - -webkit-flex-grow: 1; - -ms-flex-positive: 1; - flex-grow: 1; -} - -.c0 > * { - max-width: 100%; -} - -.c0 .inspectButtonComponent { - pointer-events: none; - opacity: 0; - -webkit-transition: opacity 250ms ease; - transition: opacity 250ms ease; -} - -.c0 .inspectButtonComponent:focus-visible { - pointer-events: auto; - opacity: 1; -} - -.c0:hover .inspectButtonComponent { - pointer-events: auto; - opacity: 1; -} - -.c4 { - padding: 12px; - background: rgba(250,251,253,0.9); - bottom: 0; - left: 0; - position: absolute; - right: 0; - top: 0; - z-index: 1000; -} - -.c5 { - height: 100%; -} - -
    -
    -
    -
    -
    - Host ID -
    -
    - - — - -
    -
    - First seen -
    -
    - -
    -
    - Last seen -
    -
    - -
    -
    -
    -
    -
    -
    - IP addresses -
    -
    - - — - -
    -
    - MAC addresses -
    -
    - - — - -
    -
    - Platform -
    -
    - - — - -
    -
    -
    -
    -
    -
    - Operating system -
    -
    - - — - -
    -
    - Family -
    -
    - - — - -
    -
    - Version -
    -
    - - — - -
    -
    - Architecture -
    -
    - - — - -
    -
    -
    -
    -
    -
    - Cloud provider -
    -
    - - — - -
    -
    - Region -
    -
    - - — - -
    -
    - Instance ID -
    -
    - - — - -
    -
    - Machine type -
    -
    - - — - -
    -
    -
    - -
    -
    -`; - -exports[`Details Panel Component DetailsPanel:NetworkDetails: rendering it should render the Network Details view in the Details Panel when the panelView is networkDetail and the ip is set 1`] = ` -.c3 { - color: #98a2b3; -} - -.c2 { - word-break: break-word; -} - -.c2 dt { - font-size: 12px !important; -} - -.c2 dd { - width: -webkit-fit-content; - width: -moz-fit-content; - width: fit-content; -} - -.c2 dd > div { - width: -webkit-fit-content; - width: -moz-fit-content; - width: fit-content; -} - -.c1 { - position: relative; -} - -.c1 .euiButtonIcon { - position: absolute; - right: 12px; - top: 6px; - z-index: 2; -} - -.c0 { - width: 100%; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-flex: 1; - -webkit-flex-grow: 1; - -ms-flex-positive: 1; - flex-grow: 1; -} - -.c0 > * { - max-width: 100%; -} - -.c0 .inspectButtonComponent { - pointer-events: none; - opacity: 0; - -webkit-transition: opacity 250ms ease; - transition: opacity 250ms ease; -} - -.c0 .inspectButtonComponent:focus-visible { - pointer-events: auto; - opacity: 1; -} - -.c0:hover .inspectButtonComponent { - pointer-events: auto; - opacity: 1; -} - -.c4 { - padding: 12px; - background: rgba(250,251,253,0.9); - bottom: 0; - left: 0; - position: absolute; - right: 0; - top: 0; - z-index: 1000; -} - -.c5 { - height: 100%; -} - -
    -
    -
    -
    -
    - Location -
    -
    - - — - -
    -
    - Autonomous system -
    -
    - - — - -
    -
    -
    -
    -
    -
    - First seen -
    -
    - -
    -
    - Last seen -
    -
    - -
    -
    -
    -
    -
    -
    - Host ID -
    -
    - - — - -
    -
    - Host name -
    -
    - - — - -
    -
    -
    - - -
    -
    -`; diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/expandable_host.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/expandable_host.test.tsx deleted file mode 100644 index 447859854c648..0000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/expandable_host.test.tsx +++ /dev/null @@ -1,99 +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 { waitFor } from '@testing-library/react'; -import React from 'react'; - -import { mockGlobalState, TestProviders } from '../../../../common/mock'; -import { ExpandableHostDetails } from './expandable_host'; -import { mockAnomalies } from '../../../../common/components/ml/mock'; -import type { Anomalies } from '../../../../common/components/ml/types'; -import { hasMlUserPermissions } from '../../../../../common/machine_learning/has_ml_user_permissions'; -import { InputsModelId } from '../../../../common/store/inputs/constants'; -const mockDispatch = jest.fn(); -jest.mock('../../../../../common/machine_learning/has_ml_user_permissions'); -jest.mock('react-redux', () => { - const original = jest.requireActual('react-redux'); - - return { - ...original, - useDispatch: () => mockDispatch, - }; -}); -jest.mock('../../../../common/components/ml/anomaly/anomaly_table_provider', () => ({ - AnomalyTableProvider: ({ - children, - }: { - children: (args: { - anomaliesData: Anomalies; - isLoadingAnomaliesData: boolean; - jobNameById: Record; - }) => React.ReactNode; - }) => children({ anomaliesData: mockAnomalies, isLoadingAnomaliesData: false, jobNameById: {} }), -})); - -describe('Expandable Host Component', () => { - beforeAll(() => { - (hasMlUserPermissions as jest.Mock).mockReturnValue(true); - }); - beforeEach(() => { - jest.clearAllMocks(); - }); - const mockProps = { - contextID: 'text-context', - hostName: 'testHostName', - scopeId: 'testScopeId', - }; - - describe('ExpandableHostDetails: rendering', () => { - test('it should render the HostOverview of the ExpandableHostDetails', () => { - const wrapper = mount( - - - - ); - - expect(wrapper.find('[data-test-subj="host-overview"]').exists()).toBe(true); - }); - - test('it should render the HostOverview of the ExpandableHostDetails with the correct indices', () => { - const wrapper = mount( - - - - ); - - expect(wrapper.find('HostOverview').prop('indexNames')).toStrictEqual( - mockGlobalState.sourcerer.sourcererScopes.default.selectedPatterns - ); - }); - - test('it should set date range to anomaly date range', async () => { - const wrapper = mount( - - - - ); - wrapper.find('[data-test-subj="anomaly-score-popover"]').first().simulate('click'); - await waitFor(() => { - wrapper - .find('button[data-test-subj="anomaly-description-narrow-range-link"]') - .first() - .simulate('click'); - }); - expect(mockDispatch).toHaveBeenCalledWith({ - type: 'x-pack/security_solution/local/inputs/SET_ABSOLUTE_RANGE_DATE_PICKER', - payload: { - id: InputsModelId.global, - from: '2019-06-15T06:00:00.000Z', - to: '2019-06-17T06:00:00.000Z', - }, - }); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/expandable_host.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/expandable_host.tsx deleted file mode 100644 index c12dbea2a81fc..0000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/expandable_host.tsx +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useCallback } from 'react'; -import styled from 'styled-components'; -import { i18n } from '@kbn/i18n'; -import { EuiTitle } from '@elastic/eui'; -import { useDispatch } from 'react-redux'; -import { InputsModelId } from '../../../../common/store/inputs/constants'; -import { HostDetailsLink } from '../../../../common/components/links'; -import { useGlobalTime } from '../../../../common/containers/use_global_time'; -import { useSourcererDataView } from '../../../../sourcerer/containers'; -import { HostOverview } from '../../../../overview/components/host_overview'; -import { setAbsoluteRangeDatePicker } from '../../../../common/store/inputs/actions'; -import type { HostItem } from '../../../../../common/search_strategy'; -import { AnomalyTableProvider } from '../../../../common/components/ml/anomaly/anomaly_table_provider'; -import { hostToCriteria } from '../../../../common/components/ml/criteria/host_to_criteria'; -import { scoreIntervalToDateTime } from '../../../../common/components/ml/score/score_interval_to_datetime'; -import { useHostDetails, ID } from '../../../../explore/hosts/containers/hosts/details'; - -interface ExpandableHostProps { - hostName: string; -} - -const StyledTitle = styled.h4` - word-break: break-all; - word-wrap: break-word; - white-space: pre-wrap; -`; - -export const ExpandableHostDetailsTitle = ({ hostName }: ExpandableHostProps) => ( - - - {i18n.translate('xpack.securitySolution.timeline.sidePanel.hostDetails.title', { - defaultMessage: 'Host details', - })} - {`: ${hostName}`} - - -); - -export const ExpandableHostDetailsPageLink = ({ hostName }: ExpandableHostProps) => ( - - {i18n.translate('xpack.securitySolution.timeline.sidePanel.hostDetails.hostDetailsPageLink', { - defaultMessage: 'View details page', - })} - -); - -export const ExpandableHostDetails = ({ - contextID, - scopeId, - hostName, - isDraggable = false, -}: ExpandableHostProps & { contextID: string; scopeId: string; isDraggable?: boolean }) => { - const { to, from, isInitializing } = useGlobalTime(); - /* - Normally `selectedPatterns` from useSourcererDataView would be where we obtain the indices, - but those indices are only loaded when viewing the pages where the sourcerer is initialized (i.e. Hosts and Overview) - When a user goes directly to the detections page, the patterns have not been loaded yet - as that information isn't used for the detections page. With this details component being accessible - from the detections page, the decision was made to get all existing index names to account for this. - Otherwise, an empty array is defaulted for the `indexNames` in the query which leads to inconsistencies in the data returned - (i.e. extraneous endpoint data is retrieved from the backend leading to endpoint data not being returned) - */ - const { selectedPatterns } = useSourcererDataView(); - const dispatch = useDispatch(); - - const [loading, { hostDetails: hostOverview }] = useHostDetails({ - endDate: to, - hostName, - indexNames: selectedPatterns, - startDate: from, - }); - const narrowDateRange = useCallback( - (score, interval) => { - const fromTo = scoreIntervalToDateTime(score, interval); - dispatch( - setAbsoluteRangeDatePicker({ - id: InputsModelId.global, - from: fromTo.from, - to: fromTo.to, - }) - ); - }, - [dispatch] - ); - return ( - - {({ isLoadingAnomaliesData, anomaliesData, jobNameById }) => ( - - )} - - ); -}; diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/index.tsx deleted file mode 100644 index 29c9c2019a4d2..0000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/index.tsx +++ /dev/null @@ -1,126 +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, - EuiFlyoutHeader, - EuiFlyoutBody, - EuiFlexItem, - EuiButtonIcon, - EuiSpacer, - EuiHorizontalRule, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import React, { useMemo } from 'react'; -import styled from 'styled-components'; -import { AssetCriticalityAccordion } from '../../../../entity_analytics/components/asset_criticality/asset_criticality_selector'; -import { - ExpandableHostDetails, - ExpandableHostDetailsPageLink, - ExpandableHostDetailsTitle, -} from './expandable_host'; - -const StyledEuiFlyoutBody = styled(EuiFlyoutBody)` - .euiFlyoutBody__overflow { - display: flex; - flex: 1; - overflow: hidden; - - .euiFlyoutBody__overflowContent { - flex: 1; - overflow-x: hidden; - overflow-y: scroll; - margin-bottom: 64px; // account for firefox, which doesn't seem to respect the bottom padding - padding: ${({ theme }) => `${theme.eui.euiSizeXS} ${theme.eui.euiSizeM} 0px`}; - } - } -`; - -const StyledEuiFlexGroup = styled(EuiFlexGroup)` - flex: 1 0 auto; -`; - -const StyledEuiFlexButtonWrapper = styled(EuiFlexItem)` - align-self: flex-start; - flex: 1 0 auto; -`; - -const StyledPanelContent = styled.div` - display: block; - height: 100%; - overflow-y: scroll; - overflow-x: hidden; -`; - -interface HostDetailsProps { - contextID: string; - scopeId: string; - expandedHost: { hostName: string }; - handleOnHostClosed: () => void; - isFlyoutView?: boolean; - isDraggable?: boolean; -} - -// eslint-disable-next-line react/display-name -export const HostDetailsPanel: React.FC = React.memo( - ({ contextID, scopeId, expandedHost, handleOnHostClosed, isDraggable, isFlyoutView }) => { - const { hostName } = expandedHost; - const entity = useMemo(() => ({ name: hostName, type: 'host' as const }), [hostName]); - if (!hostName) { - return null; - } - - return isFlyoutView ? ( - <> - - - - - - - - - - - - ) : ( - <> - - - - - - - - - - - - - - - - - - - ); - } -); diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/index.test.tsx index 23944e5e0170d..9b77d46587791 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/index.test.tsx @@ -12,7 +12,6 @@ import { mockGlobalState, TestProviders, createMockStore } from '../../../common import type { State } from '../../../common/store'; import { DetailsPanel } from '.'; import { TimelineId, TimelineTabs } from '../../../../common/types/timeline'; -import { FlowTargetSourceDest } from '../../../../common/search_strategy/security_solution/network'; import { EventDetailsPanel } from './event_details'; import { useSearchStrategy } from '../../../common/containers/use_search_strategy'; import type { ExpandedDetailTimeline } from '../../../../common/types'; @@ -64,25 +63,6 @@ describe('Details Panel Component', () => { }, }; - const hostExpandedDetail: ExpandedDetailTimeline = { - [TimelineTabs.query]: { - panelView: 'hostDetail', - params: { - hostName: 'woohoo!', - }, - }, - }; - - const networkExpandedDetail: ExpandedDetailTimeline = { - [TimelineTabs.query]: { - panelView: 'networkDetail', - params: { - ip: 'woohoo!', - flowTarget: FlowTargetSourceDest.source, - }, - }, - }; - const eventExpandedDetail: ExpandedDetailTimeline = { [TimelineTabs.query]: { panelView: 'eventDetail', @@ -288,89 +268,4 @@ describe('Details Panel Component', () => { expect(wrapper.find(EventDetailsPanel).props().isDraggable).toBeFalsy(); }); }); - - describe('DetailsPanel:HostDetails: rendering', () => { - beforeEach(() => { - mockUseSearchStrategy.mockReturnValue({ - loading: true, - result: { - hostDetails: { - host: {}, - }, - }, - error: undefined, - search: jest.fn(), - refetch: jest.fn(), - inspect: {}, - }); - const mockState = { - ...state, - timeline: { - ...state.timeline, - timelineById: { - [TimelineId.test]: state.timeline.timelineById[TimelineId.test], - [TimelineId.active]: state.timeline.timelineById[TimelineId.test], - }, - }, - }; - mockState.timeline.timelineById[TimelineId.test].expandedDetail = hostExpandedDetail; - mockState.timeline.timelineById[TimelineId.active].expandedDetail = hostExpandedDetail; - store = createMockStore(mockState); - }); - - afterEach(() => { - mockUseSearchStrategy.mockReset(); - }); - - test('it should render the Host Details view in the Details Panel when the panelView is hostDetail and the hostName is set', () => { - const wrapper = mount( - - - - ); - - expect(wrapper.find('ExpandableHostDetails').first().render()).toMatchSnapshot(); - }); - }); - - describe('DetailsPanel:NetworkDetails: rendering', () => { - beforeEach(() => { - mockUseSearchStrategy.mockReturnValue({ - loading: true, - result: { - networkDetails: {}, - }, - search: jest.fn(), - refetch: jest.fn(), - inspect: {}, - }); - const mockState = { - ...state, - timeline: { - ...state.timeline, - timelineById: { - [TimelineId.test]: state.timeline.timelineById[TimelineId.test], - [TimelineId.active]: state.timeline.timelineById[TimelineId.test], - }, - }, - }; - mockState.timeline.timelineById[TimelineId.test].expandedDetail = networkExpandedDetail; - mockState.timeline.timelineById[TimelineId.active].expandedDetail = networkExpandedDetail; - store = createMockStore(mockState); - }); - - afterEach(() => { - mockUseSearchStrategy.mockReset(); - }); - - test('it should render the Network Details view in the Details Panel when the panelView is networkDetail and the ip is set', () => { - const wrapper = mount( - - - - ); - - expect(wrapper.find('ExpandableNetworkDetails').render()).toMatchSnapshot(); - }); - }); }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/index.tsx index 4050b7679b97a..7c9ce280360a0 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/index.tsx @@ -20,8 +20,6 @@ import type { RunTimeMappings } from '../../../sourcerer/store/model'; import { TimelineId, TimelineTabs } from '../../../../common/types/timeline'; import { useDeepEqualSelector } from '../../../common/hooks/use_selector'; import { EventDetailsPanel } from './event_details'; -import { HostDetailsPanel } from './host_details'; -import { NetworkDetailsPanel } from './network_details'; interface DetailsPanelProps { browserFields: BrowserFields; @@ -103,7 +101,6 @@ export const DetailsPanel = React.memo( let visiblePanel = null; // store in variable to make return statement more readable let panelSize: EuiFlyoutProps['size'] = 's'; let flyoutUniqueKey = scopeId; - const contextID = `${scopeId}-${activeTab}`; const isDraggable = scopeId === TimelineId.active && activeTab === TimelineTabs.query; if (currentTabDetail?.panelView === 'eventDetail' && currentTabDetail?.params?.eventId) { @@ -125,33 +122,6 @@ export const DetailsPanel = React.memo( ); } - if (currentTabDetail?.panelView === 'hostDetail' && currentTabDetail?.params?.hostName) { - flyoutUniqueKey = currentTabDetail.params.hostName; - visiblePanel = ( - - ); - } - - if (currentTabDetail?.panelView === 'networkDetail' && currentTabDetail?.params?.ip) { - flyoutUniqueKey = currentTabDetail.params.ip; - visiblePanel = ( - - ); - } - return isFlyoutView ? ( ( - - - {i18n.translate('xpack.securitySolution.timeline.sidePanel.networkDetails.title', { - defaultMessage: 'Network details', - })} - {`: ${ip}`} - - -); - -export const ExpandableNetworkDetailsPageLink = ({ - expandedNetwork: { ip, flowTarget }, -}: ExpandableNetworkProps) => ( - - {i18n.translate( - 'xpack.securitySolution.timeline.sidePanel.networkDetails.networkDetailsPageLink', - { - defaultMessage: 'View details page', - } - )} - -); - -export const ExpandableNetworkDetails = ({ - contextID, - expandedNetwork, - isDraggable, -}: ExpandableNetworkProps & { contextID: string; isDraggable?: boolean }) => { - const { ip, flowTarget } = expandedNetwork; - const dispatch = useDispatch(); - const { to, from, isInitializing } = useGlobalTime(); - const getGlobalQuerySelector = useMemo(() => inputsSelectors.globalQuerySelector(), []); - const getGlobalFiltersQuerySelector = useMemo( - () => inputsSelectors.globalFiltersQuerySelector(), - [] - ); - - const query = useDeepEqualSelector(getGlobalQuerySelector); - const filters = useDeepEqualSelector(getGlobalFiltersQuerySelector); - - const type = networkModel.NetworkType.details; - const narrowDateRange = useCallback( - (score, interval) => { - const fromTo = scoreIntervalToDateTime(score, interval); - dispatch( - setAbsoluteRangeDatePicker({ - id: InputsModelId.global, - from: fromTo.from, - to: fromTo.to, - }) - ); - }, - [dispatch] - ); - const { - services: { uiSettings }, - } = useKibana(); - - const { indicesExist, indexPattern, selectedPatterns } = useSourcererDataView(); - const [filterQuery, kqlError] = convertToBuildEsQuery({ - config: getEsQueryConfig(uiSettings), - indexPattern, - queries: [query], - filters, - }); - - const [loading, { id, networkDetails }] = useNetworkDetails({ - skip: isInitializing || filterQuery === undefined, - filterQuery, - indexNames: selectedPatterns, - ip, - }); - - useInvalidFilterQuery({ id, filterQuery, kqlError, query, startDate: from, endDate: to }); - const { jobNameById } = useInstalledSecurityJobNameById(); - const jobIds = useMemo(() => Object.keys(jobNameById), [jobNameById]); - const [isLoadingAnomaliesData, anomaliesData] = useAnomaliesTableData({ - criteriaFields: networkToCriteria(ip, flowTarget), - startDate: from, - endDate: to, - skip: isInitializing, - jobIds, - aggregationInterval: 'auto', - }); - - return indicesExist ? ( - - ) : ( - - ); -}; diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/network_details/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/network_details/index.tsx deleted file mode 100644 index 3ca2ed63ffa81..0000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/network_details/index.tsx +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - EuiFlexGroup, - EuiFlyoutHeader, - EuiFlyoutBody, - EuiFlexItem, - EuiButtonIcon, - EuiSpacer, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import React from 'react'; -import styled from 'styled-components'; -import type { FlowTargetSourceDest } from '../../../../../common/search_strategy'; -import { - ExpandableNetworkDetailsTitle, - ExpandableNetworkDetailsPageLink, - ExpandableNetworkDetails, -} from './expandable_network'; - -const StyledEuiFlyoutBody = styled(EuiFlyoutBody)` - .euiFlyoutBody__overflow { - display: flex; - flex: 1; - overflow-x: hidden; - overflow-y: scroll; - - .euiFlyoutBody__overflowContent { - flex: 1; - overflow-x: hidden; - overflow-y: scroll; - padding: ${({ theme }) => `${theme.eui.euiSizeXS} ${theme.eui.euiSizeM} 64px`}; - } - } -`; - -const StyledEuiFlexGroup = styled(EuiFlexGroup)` - flex: 1 0 auto; -`; - -const StyledEuiFlexButtonWrapper = styled(EuiFlexItem)` - align-self: flex-start; - flex: 1 0 auto; -`; - -const StyledPanelContent = styled.div` - display: block; - height: 100%; - overflow-y: scroll; - overflow-x: hidden; -`; - -interface NetworkDetailsProps { - contextID: string; - expandedNetwork: { ip: string; flowTarget: FlowTargetSourceDest }; - handleOnNetworkClosed: () => void; - isFlyoutView?: boolean; - isDraggable?: boolean; -} - -// eslint-disable-next-line react/display-name -export const NetworkDetailsPanel = React.memo( - ({ - contextID, - expandedNetwork, - handleOnNetworkClosed, - isFlyoutView, - isDraggable, - }: NetworkDetailsProps) => { - const { ip } = expandedNetwork; - - return isFlyoutView ? ( - <> - - - - - - - - - - - ) : ( - <> - - - - - - - - - - - - - - - - - - ); - } -); diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/columns.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/columns.tsx index 7ea3168c406a0..7c20db93d2e3e 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/columns.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/columns.tsx @@ -9,7 +9,7 @@ import { css } from '@emotion/react'; import React from 'react'; import { euiThemeVars } from '@kbn/ui-theme'; import type { EuiBasicTableColumn } from '@elastic/eui'; -import { DefaultFieldRenderer } from '../../field_renderers/field_renderers'; +import { DefaultFieldRenderer } from '../../field_renderers/default_renderer'; import type { ManagedUsersTableColumns, ManagedUserTable } from './types'; import * as i18n from './translations'; import { defaultToEmptyTag } from '../../../../common/components/empty_value'; 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 index 479d4d0defc1f..c1cc3fee19d49 100644 --- 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 @@ -38,7 +38,6 @@ import { getRowRenderer } from '../renderers/get_row_renderer'; import { StatefulRowRenderer } from './stateful_row_renderer'; import { NOTES_BUTTON_CLASS_NAME } from '../../properties/helpers'; import { timelineDefaults } from '../../../../store/defaults'; -import { useGetMappedNonEcsValue } from '../data_driven_columns'; import { StatefulEventContext } from '../../../../../common/components/events_viewer/stateful_event_context'; import type { ControlColumnProps, @@ -126,23 +125,6 @@ const StatefulEventComponent: React.FC = ({ const expandedDetail = useDeepEqualSelector( (state) => (getTimeline(state, timelineId) ?? timelineDefaults).expandedDetail ?? {} ); - const hostNameArr = useGetMappedNonEcsValue({ data: event?.data, fieldName: 'host.name' }); - - const hostName = useMemo(() => { - return hostNameArr && hostNameArr.length > 0 ? hostNameArr[0] : null; - }, [hostNameArr]); - const hostIpList = useGetMappedNonEcsValue({ data: event?.data, fieldName: 'host.ip' }); - const sourceIpList = useGetMappedNonEcsValue({ data: event?.data, fieldName: 'source.ip' }); - const destinationIpList = useGetMappedNonEcsValue({ - data: event?.data, - fieldName: 'destination.ip', - }); - const hostIPAddresses = useMemo(() => { - const hostIps = hostIpList ?? []; - const sourceIps = sourceIpList ?? []; - const destinationIps = destinationIpList ?? []; - return new Set([...hostIps, ...sourceIps, ...destinationIps]); - }, [destinationIpList, sourceIpList, hostIpList]); const activeTab = tabType ?? TimelineTabs.query; const activeExpandedDetail = expandedDetail[activeTab]; @@ -151,11 +133,6 @@ const StatefulEventComponent: React.FC = ({ const isDetailPanelExpanded: boolean = (activeExpandedDetail?.panelView === 'eventDetail' && activeExpandedDetail?.params?.eventId === eventId) || - (activeExpandedDetail?.panelView === 'hostDetail' && - activeExpandedDetail?.params?.hostName === hostName) || - (activeExpandedDetail?.panelView === 'networkDetail' && - activeExpandedDetail?.params?.ip && - hostIPAddresses?.has(activeExpandedDetail?.params?.ip)) || false; const getNotesByIds = useMemo(() => appSelectors.notesByIdsSelector(), []); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/formatted_field_udt.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/formatted_field_udt.tsx index 545a198593fe8..bd0c01019d63c 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/formatted_field_udt.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/formatted_field_udt.tsx @@ -6,6 +6,7 @@ */ import type { EuiDataGridCellValueElementProps } from '@elastic/eui'; +import type { ReactElement } from 'react'; import React from 'react'; import type { ColumnHeaderOptions, TimelineItem } from '@kbn/timelines-plugin/common'; @@ -23,7 +24,7 @@ export const getFormattedFields = ({ }) => { return headers.reduce( ( - obj: Record React.ReactNode>, + obj: Record ReactElement>, header: ColumnHeaderOptions ) => { obj[header.id] = function UnifiedFieldRender(props: EuiDataGridCellValueElementProps) { diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/query_tab_unified_components.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/query_tab_unified_components.test.tsx index de6e85a07f8af..2c5a1687f30ae 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/query_tab_unified_components.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/query_tab_unified_components.test.tsx @@ -86,10 +86,12 @@ jest.mock('../../../../../common/lib/kibana'); jest.mock(`@kbn/ebt/client`); const mockOpenFlyout = jest.fn(); +const mockCloseFlyout = jest.fn(); jest.mock('@kbn/expandable-flyout', () => { return { useExpandableFlyoutApi: () => ({ openFlyout: mockOpenFlyout, + closeFlyout: mockCloseFlyout, }), TestProvider: ({ children }: PropsWithChildren<{}>) => <>{children}, }; @@ -781,6 +783,54 @@ describe('query tab with unified timeline', () => { ); }); + describe('Leading actions - expand event', () => { + it( + 'should expand and collapse event correctly', + async () => { + renderTestComponents(); + expect(await screen.findByTestId('discoverDocTable')).toBeVisible(); + + expect(screen.getByTestId('docTableExpandToggleColumn').firstChild).toHaveAttribute( + 'data-euiicon-type', + 'expand' + ); + + // Open Flyout + fireEvent.click(screen.getByTestId('docTableExpandToggleColumn')); + + await waitFor(() => { + expect(mockOpenFlyout).toHaveBeenNthCalledWith(1, { + right: { + id: 'document-details-right', + params: { + id: '1', + indexName: '', + scopeId: TimelineId.test, + }, + }, + }); + }); + + expect(screen.getByTestId('docTableExpandToggleColumn').firstChild).toHaveAttribute( + 'data-euiicon-type', + 'minimize' + ); + + // Close Flyout + fireEvent.click(screen.getByTestId('docTableExpandToggleColumn')); + + await waitFor(() => { + expect(mockCloseFlyout).toHaveBeenNthCalledWith(1); + expect(screen.getByTestId('docTableExpandToggleColumn').firstChild).toHaveAttribute( + 'data-euiicon-type', + 'expand' + ); + }); + }, + SPECIAL_TEST_TIMEOUT + ); + }); + describe('Leading actions - notes', () => { describe('securitySolutionNotesEnabled = true', () => { beforeEach(() => { diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/custom_timeline_data_grid_body.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/custom_timeline_data_grid_body.tsx index 284452074a82a..fc98c72587e2e 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/custom_timeline_data_grid_body.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/custom_timeline_data_grid_body.tsx @@ -15,7 +15,7 @@ import styled from 'styled-components'; import type { RowRenderer } from '../../../../../../common/types'; import { TIMELINE_EVENT_DETAIL_ROW_ID } from '../../body/constants'; import { useStatefulRowRenderer } from '../../body/events/stateful_row_renderer/use_stateful_row_renderer'; -import { useGetEventTypeRowClassName } from './use_get_event_type_row_classname'; +import { getEventTypeRowClassName } from './get_event_type_row_classname'; export type CustomTimelineDataGridBodyProps = EuiDataGridCustomBodyProps & { rows: Array | undefined; @@ -181,7 +181,7 @@ const CustomDataGridSingleRow = memo(function CustomDataGridSingleRow( : {}, [canShowRowRenderer] ); - const eventTypeRowClassName = useGetEventTypeRowClassName(rowData.ecs); + const eventTypeRowClassName = useMemo(() => getEventTypeRowClassName(rowData.ecs), [rowData.ecs]); return ( { +describe('getEventTypeRowClassName', () => { it('should return rawEvent', () => { - const { result } = renderHook(() => useGetEventTypeRowClassName(mockEvent)); - expect(result.current).toEqual('rawEvent'); + const result = getEventTypeRowClassName(mockEvent); + expect(result).toEqual('rawEvent'); }); it('should contain eqlSequence', () => { - const { result } = renderHook(() => useGetEventTypeRowClassName(mockBuildingBlockAlert)); - expect(result.current).toContain('eqlSequence'); + const result = getEventTypeRowClassName(mockBuildingBlockAlert); + expect(result).toContain('eqlSequence'); }); it('should contain buildingBlockType', () => { - const { result } = renderHook(() => useGetEventTypeRowClassName(mockBuildingBlockAlert)); - expect(result.current).toContain('buildingBlockType'); + const result = getEventTypeRowClassName(mockBuildingBlockAlert); + expect(result).toContain('buildingBlockType'); }); it('should return eqlNonSequence', () => { - const { result } = renderHook(() => useGetEventTypeRowClassName(mockOddEqlEvent)); - expect(result.current).toEqual('eqlNonSequence'); + const result = getEventTypeRowClassName(mockOddEqlEvent); + expect(result).toEqual('eqlNonSequence'); }); it('should return nonRawEvent', () => { - const { result } = renderHook(() => useGetEventTypeRowClassName(mockAlert)); - expect(result.current).toEqual('nonRawEvent'); + const result = getEventTypeRowClassName(mockAlert); + expect(result).toEqual('nonRawEvent'); }); }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/get_event_type_row_classname.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/get_event_type_row_classname.ts new file mode 100644 index 0000000000000..b6058af189c9d --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/get_event_type_row_classname.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { TimelineItem } from '@kbn/timelines-plugin/common'; +import { getEventType, isEvenEqlSequence, isEventBuildingBlockType } from '../../body/helpers'; + +export const getEventTypeRowClassName = (ecsData: TimelineItem['ecs']) => { + const eventType = getEventType(ecsData); + const eventTypeClassName = + eventType === 'raw' + ? 'rawEvent' + : eventType === 'eql' + ? isEvenEqlSequence(ecsData) + ? 'eqlSequence' + : 'eqlNonSequence' + : 'nonRawEvent'; + + const buildingBlockTypeClassName = isEventBuildingBlockType(ecsData) ? 'buildingBlockType' : ''; + + return `${eventTypeClassName} ${buildingBlockTypeClassName}`.trim(); +}; 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 b9807e08572b4..33e977f6a2999 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 @@ -17,7 +17,7 @@ import type { ComponentProps } from 'react'; import { getColumnHeaders } from '../../body/column_headers/helpers'; import { mockSourcererScope } from '../../../../../sourcerer/containers/mocks'; import { timelineActions } from '../../../../store'; -import { useUnifiedTableExpandableFlyout } from '../hooks/use_unified_timeline_expandable_flyout'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; jest.mock('../../../../../sourcerer/containers'); @@ -35,9 +35,8 @@ const onEventClosedMock = jest.fn(); const onChangePageMock = jest.fn(); const openFlyoutMock = jest.fn(); -const closeFlyoutMock = jest.fn(); -jest.mock('../hooks/use_unified_timeline_expandable_flyout'); +jest.mock('@kbn/expandable-flyout'); const initialEnrichedColumns = getColumnHeaders( defaultUdtHeaders, @@ -97,9 +96,8 @@ const getTimelineFromStore = ( describe('unified data table', () => { beforeEach(() => { (useSourcererDataView as jest.Mock).mockReturnValue(mockSourcererScope); - (useUnifiedTableExpandableFlyout as jest.Mock).mockReturnValue({ + (useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openFlyout: openFlyoutMock, - closeFlyout: closeFlyoutMock, }); }); afterEach(() => { 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 e4433a0fd56a1..9deca4a332d9a 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 @@ -13,6 +13,8 @@ import type { UnifiedDataTableProps } from '@kbn/unified-data-table'; import { UnifiedDataTable, DataLoadingState } from '@kbn/unified-data-table'; import type { DataView } from '@kbn/data-views-plugin/public'; import type { EuiDataGridCustomBodyProps, EuiDataGridProps } from '@elastic/eui'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { useOnExpandableFlyoutClose } from '../../../../../flyout/shared/hooks/use_on_expandable_flyout_close'; import { DocumentDetailsRightPanelKey } from '../../../../../flyout/document_details/shared/constants/panel_keys'; import { selectTimelineById } from '../../../../store/selectors'; import { RowRendererCount } from '../../../../../../common/api/timeline'; @@ -43,7 +45,6 @@ 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 { useUnifiedTableExpandableFlyout } from '../hooks/use_unified_timeline_expandable_flyout'; import type { UnifiedTimelineDataGridCellContext } from '../../types'; export const SAMPLE_SIZE_SETTING = 500; @@ -138,13 +139,12 @@ export const TimelineDataTableComponent: React.FC = memo( const [expandedDoc, setExpandedDoc] = useState(); const [fetchedPage, setFechedPage] = useState(0); - const onCloseExpandableFlyout = useCallback(() => { + const onCloseExpandableFlyout = useCallback((id: string) => { setExpandedDoc((prev) => (!prev ? prev : undefined)); }, []); - const { openFlyout, closeFlyout } = useUnifiedTableExpandableFlyout({ - onClose: onCloseExpandableFlyout, - }); + const { closeFlyout, openFlyout } = useExpandableFlyoutApi(); + useOnExpandableFlyoutClose({ callback: onCloseExpandableFlyout }); const showTimeCol = useMemo(() => !!dataView && !!dataView.timeFieldName, [dataView]); @@ -152,7 +152,7 @@ export const TimelineDataTableComponent: React.FC = memo( selectTimelineById(state, timelineId) ); - const tableRows = useMemo( + const { tableRows, tableStylesOverride } = useMemo( () => transformTimelineItemToUnifiedRows({ events, dataView }), [events, dataView] ); @@ -187,6 +187,7 @@ export const TimelineDataTableComponent: React.FC = memo( } } else { closeFlyout(); + setExpandedDoc(undefined); } }, [tableRows, handleOnEventDetailPanelOpened, closeFlyout] @@ -372,9 +373,10 @@ export const TimelineDataTableComponent: React.FC = memo( { - const eventType = useMemo(() => getEventType(ecsData), [ecsData]); - const eventTypeClassName = useMemo( - () => - eventType === 'raw' - ? 'rawEvent' - : eventType === 'eql' - ? isEvenEqlSequence(ecsData) - ? 'eqlSequence' - : 'eqlNonSequence' - : 'nonRawEvent', - [ecsData, eventType] - ); - const buildingBlockTypeClassName = useMemo( - () => (isEventBuildingBlockType(ecsData) ? 'buildingBlockType' : ''), - [ecsData] - ); - - return useMemo( - () => `${eventTypeClassName} ${buildingBlockTypeClassName}`.trim(), - [eventTypeClassName, buildingBlockTypeClassName] - ); -}; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/hooks/use_unified_timeline_expandable_flyout.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/hooks/use_unified_timeline_expandable_flyout.test.tsx deleted file mode 100644 index a1b89511de6c3..0000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/hooks/use_unified_timeline_expandable_flyout.test.tsx +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { renderHook } from '@testing-library/react-hooks'; -import { useUnifiedTableExpandableFlyout } from './use_unified_timeline_expandable_flyout'; -import { useLocation } from 'react-router-dom'; -import { URL_PARAM_KEY } from '../../../../../common/hooks/use_url_state'; -import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; - -jest.mock('@kbn/kibana-react-plugin/public'); -jest.mock('react-router-dom', () => { - return { - useLocation: jest.fn(), - }; -}); -jest.mock('@kbn/expandable-flyout'); - -const onFlyoutCloseMock = jest.fn(); - -describe('useUnifiedTimelineExpandableFlyout', () => { - describe('when expandable flyout is enabled', () => { - beforeEach(() => { - (useExpandableFlyoutApi as jest.Mock).mockReturnValue({ - openFlyout: jest.fn(), - closeFlyout: jest.fn(), - }); - - (useLocation as jest.Mock).mockReturnValue({ - search: `${URL_PARAM_KEY.timelineFlyout}=(test:value)`, - }); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - it('should mark flyout as close when location has empty `timelineFlyout`', () => { - const { result, rerender } = renderHook(() => - useUnifiedTableExpandableFlyout({ - onClose: onFlyoutCloseMock, - }) - ); - - (useLocation as jest.Mock).mockReturnValue({ - search: `${URL_PARAM_KEY.timelineFlyout}=()`, - }); - - rerender(); - - expect(result.current.isTimelineExpandableFlyoutOpen).toBe(false); - expect(onFlyoutCloseMock).toHaveBeenCalledTimes(1); - }); - - it('should call user provided close handler when flyout is closed', () => { - const { result } = renderHook(() => - useUnifiedTableExpandableFlyout({ - onClose: onFlyoutCloseMock, - }) - ); - - result.current.closeFlyout(); - - expect(onFlyoutCloseMock).toHaveBeenCalledTimes(1); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/hooks/use_unified_timeline_expandable_flyout.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/hooks/use_unified_timeline_expandable_flyout.tsx deleted file mode 100644 index fb28b6f44f367..0000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/hooks/use_unified_timeline_expandable_flyout.tsx +++ /dev/null @@ -1,72 +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 { useCallback, useEffect, useMemo, useState } from 'react'; -import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; -import { useLocation } from 'react-router-dom'; -import { URL_PARAM_KEY } from '../../../../../common/hooks/use_url_state'; - -const EMPTY_TIMELINE_FLYOUT_SEARCH_PARAMS = '()'; - -interface UseUnifiedTableExpandableFlyoutArgs { - onClose?: () => void; -} - -export const useUnifiedTableExpandableFlyout = ({ - onClose, -}: UseUnifiedTableExpandableFlyoutArgs) => { - const location = useLocation(); - - const { openFlyout, closeFlyout } = useExpandableFlyoutApi(); - - const closeFlyoutWithEffect = useCallback(() => { - closeFlyout(); - onClose?.(); - }, [onClose, closeFlyout]); - - const isFlyoutOpen = useMemo(() => { - /** - * Currently, if new expandable flyout is closed, there is no way for - * consumer to trigger an effect `onClose` of flyout. So, we are using - * this hack to know if flyout is open or not. - * - * Raised: https://github.com/elastic/kibana/issues/179520 - * - * */ - const searchParams = new URLSearchParams(location.search); - return ( - searchParams.has(URL_PARAM_KEY.timelineFlyout) && - searchParams.get(URL_PARAM_KEY.timelineFlyout) !== EMPTY_TIMELINE_FLYOUT_SEARCH_PARAMS - ); - }, [location.search]); - - const [isTimelineExpandableFlyoutOpen, setIsTimelineExpandableFlyoutOpen] = - useState(isFlyoutOpen); - - useEffect(() => { - setIsTimelineExpandableFlyoutOpen((prev) => { - if (prev === isFlyoutOpen) { - return prev; - } - if (!isFlyoutOpen && onClose) { - // run onClose only when isFlyoutOpen changed from true to false - // should not be needed when - // https://github.com/elastic/kibana/issues/179520 - // is resolved - - onClose(); - } - return isFlyoutOpen; - }); - }, [isFlyoutOpen, onClose]); - - return { - isTimelineExpandableFlyoutOpen, - openFlyout, - closeFlyout: closeFlyoutWithEffect, - }; -}; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/styles.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/styles.tsx index 2d32767ea19c0..6c9ca63cb4e68 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/styles.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/styles.tsx @@ -100,7 +100,8 @@ export const StyledTimelineUnifiedDataTable = styled.div.attrs(({ className = '' border-radius: 8px; } - .udtTimeline .euiDataGridRow:has(.buildingBlockType) { + .udtTimeline .euiDataGridRow:has(.buildingBlockType), + .udtTimeline .euiDataGridRow.buildingBlockType { background: repeating-linear-gradient( 127deg, rgba(245, 167, 0, 0.2), @@ -109,9 +110,10 @@ export const StyledTimelineUnifiedDataTable = styled.div.attrs(({ className = '' rgba(245, 167, 0, 0.05) 10px ); } - .udtTimeline .euiDataGridRow:has(.eqlSequence) { + .udtTimeline .euiDataGridRow:has(.eqlSequence), + .udtTimeline .euiDataGridRow.eqlSequence { .euiDataGridRowCell--firstColumn, - .euiDataGridRowCell--lastColumn, + .euiDataGridRowCell--controlColumn.euiDataGridRowCell--lastColumn, .udt--customRow { ${({ theme }) => `border-left: 4px solid ${theme.eui.euiColorPrimary}`}; } @@ -123,9 +125,10 @@ export const StyledTimelineUnifiedDataTable = styled.div.attrs(({ className = '' rgba(0, 107, 180, 0.05) 10px ); } - .udtTimeline .euiDataGridRow:has(.eqlNonSequence) { + .udtTimeline .euiDataGridRow:has(.eqlNonSequence), + .udtTimeline .euiDataGridRow.eqlNonSequence { .euiDataGridRowCell--firstColumn, - .euiDataGridRowCell--lastColumn, + .euiDataGridRowCell--controlColumn.euiDataGridRowCell--lastColumn, .udt--customRow { ${({ theme }) => `border-left: 4px solid ${theme.eui.euiColorAccent};`} } @@ -137,16 +140,18 @@ export const StyledTimelineUnifiedDataTable = styled.div.attrs(({ className = '' rgba(221, 10, 115, 0.05) 10px ); } - .udtTimeline .euiDataGridRow:has(.nonRawEvent) { + .udtTimeline .euiDataGridRow:has(.nonRawEvent), + .udtTimeline .euiDataGridRow.nonRawEvent { .euiDataGridRowCell--firstColumn, - .euiDataGridRowCell--lastColumn, + .euiDataGridRowCell--controlColumn.euiDataGridRowCell--lastColumn, .udt--customRow { ${({ theme }) => `border-left: 4px solid ${theme.eui.euiColorWarning};`} } } - .udtTimeline .euiDataGridRow:has(.rawEvent) { + .udtTimeline .euiDataGridRow:has(.rawEvent), + .udtTimeline .euiDataGridRow.rawEvent { .euiDataGridRowCell--firstColumn, - .euiDataGridRowCell--lastColumn, + .euiDataGridRowCell--controlColumn.euiDataGridRowCell--lastColumn, .udt--customRow { ${({ theme }) => `border-left: 4px solid ${theme.eui.euiColorLightShade};`} } diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/utils.test.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/utils.test.ts index ae336d6bf4b79..af346e9addabd 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/utils.test.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/utils.test.ts @@ -10,22 +10,27 @@ import { fieldFormatsMock } from '@kbn/field-formats-plugin/common/mocks'; import { mockSourcererScope } from '../../../../sourcerer/containers/mocks'; import { mockTimelineData } from '../../../../common/mock'; +import type { TransformTimelineItemToUnifiedRowsReturn } from './utils'; import { transformTimelineItemToUnifiedRows } from './utils'; const testTimelineData = mockTimelineData; describe('utils', () => { describe('transformTimelineItemToUnifiedRows', () => { - it('should return correct result', () => { - const result = transformTimelineItemToUnifiedRows({ + let result: TransformTimelineItemToUnifiedRowsReturn; + beforeAll(() => { + result = transformTimelineItemToUnifiedRows({ events: testTimelineData, dataView: new DataView({ spec: mockSourcererScope.sourcererDataView, fieldFormats: fieldFormatsMock, }), }); + }); - expect(result[0]).toEqual({ + it('should return correct result', () => { + const { tableRows } = result; + expect(tableRows[0]).toEqual({ _id: testTimelineData[0]._id, id: testTimelineData[0]._id, data: testTimelineData[0].data, @@ -57,5 +62,53 @@ describe('utils', () => { }, }); }); + + it('should return correct table styles', () => { + const { tableStylesOverride } = result; + expect(tableStylesOverride).toMatchInlineSnapshot(` + Object { + "border": "horizontal", + "cellPadding": "l", + "fontSize": "s", + "header": "underline", + "rowClasses": Object { + "0": "rawEvent", + "1": "rawEvent", + "10": "rawEvent", + "11": "rawEvent", + "12": "rawEvent", + "13": "rawEvent", + "14": "rawEvent", + "15": "rawEvent", + "16": "rawEvent", + "17": "rawEvent", + "18": "rawEvent", + "19": "rawEvent", + "2": "rawEvent", + "20": "rawEvent", + "21": "rawEvent", + "22": "rawEvent", + "23": "rawEvent", + "24": "rawEvent", + "25": "rawEvent", + "26": "rawEvent", + "27": "rawEvent", + "28": "rawEvent", + "29": "rawEvent", + "3": "rawEvent", + "30": "rawEvent", + "31": "rawEvent", + "4": "rawEvent", + "5": "rawEvent", + "6": "rawEvent", + "7": "rawEvent", + "8": "rawEvent", + "9": "rawEvent", + }, + "rowHover": "highlight", + "stripes": true, + } + `); + }); }); }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/utils.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/utils.ts index 20b769455d3ea..f76b3c45c303e 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/utils.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/utils.ts @@ -5,23 +5,39 @@ * 2.0. */ +import type { EuiDataGridStyle } from '@elastic/eui'; import { flattenHit } from '@kbn/data-service'; import type { DataView } from '@kbn/data-views-plugin/public'; import type { DataTableRecord } from '@kbn/discover-utils/types'; +import { GRID_STYLE } from '@kbn/unified-data-table/src/constants'; import type { TimelineItem } from '../../../../../common/search_strategy'; +import { getEventTypeRowClassName } from './data_table/get_event_type_row_classname'; interface TransformTimelineItemToUnifiedRows { events: TimelineItem[]; dataView: DataView; } +export interface TransformTimelineItemToUnifiedRowsReturn { + tableRows: Array; + tableStylesOverride: EuiDataGridStyle; +} + export function transformTimelineItemToUnifiedRows( args: TransformTimelineItemToUnifiedRows -): Array { +): TransformTimelineItemToUnifiedRowsReturn { const { events, dataView } = args; - const unifiedDataTableRows = events.map(({ _id, _index, ecs, data }) => { + const rowClasses: EuiDataGridStyle['rowClasses'] = {}; + const unifiedDataTableRows = events.map(({ _id, _index, ecs, data }, index) => { const _source = ecs as unknown as Record; const hit = { _id, _index: String(_index), _source }; + + /** + * Side effect + * We need to add a custom className for each row based on the event type. Rather than looping twice + * we take advantage of this map to set the styles for each row + */ + rowClasses[index] = getEventTypeRowClassName(ecs); /* * Ideally for unified data table we only need raw and flattened keys * but we use this transformed data within other parts of security solution @@ -40,5 +56,5 @@ export function transformTimelineItemToUnifiedRows( }; }); - return unifiedDataTableRows; + return { tableRows: unifiedDataTableRows, tableStylesOverride: { ...GRID_STYLE, rowClasses } }; } diff --git a/x-pack/plugins/security_solution/public/timelines/containers/local_storage/index.test.ts b/x-pack/plugins/security_solution/public/timelines/containers/local_storage/index.test.ts index 94f03268a23b2..82f3943ae4e34 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/local_storage/index.test.ts +++ b/x-pack/plugins/security_solution/public/timelines/containers/local_storage/index.test.ts @@ -872,12 +872,7 @@ describe('SiemLocalStorage', () => { ], dataViewId: null, deletedEventIds: [], - expandedDetail: { - query: { - params: { hostName: 'Host-riizqhdnoy' }, - panelView: 'hostDetail', - }, - }, + expandedDetail: {}, filters: [], indexNames: [], isSelectAllChecked: false, 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 a45bd4e040d4e..49e16b927c0ca 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 @@ -8,7 +8,7 @@ import React from 'react'; import { renderHook } from '@testing-library/react-hooks'; import { useCreateTimeline } from './use_create_timeline'; import type { TimeRange } from '../../common/store/inputs/model'; -import { TimelineType } from '../../../common/api/timeline'; +import { RowRendererCount, TimelineType } from '../../../common/api/timeline'; import { TimelineId } from '../../../common/types'; import { useDiscoverInTimelineContext } from '../../common/components/discover_in_timeline/use_discover_in_timeline_context'; import { timelineActions } from '../store'; @@ -79,6 +79,7 @@ describe('useCreateTimeline', () => { ); expect(createTimeline.mock.calls[0][0].show).toEqual(true); expect(createTimeline.mock.calls[0][0].updated).toEqual(undefined); + expect(createTimeline.mock.calls[0][0].excludedRowRendererIds).toHaveLength(RowRendererCount); expect(setSelectedDataView.mock.calls[0][0].id).toEqual(SourcererScopeName.timeline); expect(setSelectedDataView.mock.calls[0][0].selectedDataViewId).toEqual( mockGlobalState.sourcerer.defaultDataView.id 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 1212e78b49305..31404b54957f7 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 @@ -13,6 +13,7 @@ import { timelineActions } from '../store'; import { useTimelineFullScreen } from '../../common/containers/use_full_screen'; import { TimelineId } from '../../../common/types/timeline'; import type { TimelineTypeLiteral } from '../../../common/api/timeline'; +import { TimelineType } from '../../../common/api/timeline'; import { useDeepEqualSelector } from '../../common/hooks/use_selector'; import { inputsActions, inputsSelectors } from '../../common/store/inputs'; import { sourcererActions, sourcererSelectors } from '../../sourcerer/store'; @@ -86,9 +87,10 @@ export const useCreateTimeline = ({ show, timelineType, updated: undefined, - excludedRowRendererIds: !unifiedComponentsInTimelineDisabled - ? timelineDefaults.excludedRowRendererIds - : [], + excludedRowRendererIds: + !unifiedComponentsInTimelineDisabled && timelineType !== TimelineType.template + ? timelineDefaults.excludedRowRendererIds + : [], }) ); 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 4b1d67ff88718..abc576fe3c9d9 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 @@ -6,6 +6,7 @@ */ import type { RequestHandler } from '@kbn/core/server'; +import { stringify } from '../../utils/stringify'; import type { EndpointActionFileInfoParams } from '../../../../common/api/endpoint'; import { EndpointActionFileInfoSchema } from '../../../../common/api/endpoint'; import type { ResponseActionsClient } from '../../services'; @@ -35,6 +36,8 @@ export const getActionFileInfoRouteHandler = ( const logger = endpointContext.logFactory.get('actionFileInfo'); return async (context, req, res) => { + logger.debug(() => `Get response action file info:\n${stringify(req.params)}`); + const { action_id: requestActionId, file_id: fileId } = req.params; const coreContext = await context.core; diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/lib/base_response_actions_client.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/lib/base_response_actions_client.ts index 927875855eb11..ba2b50841d385 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/lib/base_response_actions_client.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/lib/base_response_actions_client.ts @@ -450,7 +450,7 @@ export abstract class ResponseActionsClientImpl implements ResponseActionsClient comment: actionRequest.comment ?? undefined, ...(actionRequest.alert_ids ? { alert_id: actionRequest.alert_ids } : {}), ...(actionRequest.hosts ? { hosts: actionRequest.hosts } : {}), - parameters: actionRequest.parameters as EndpointActionDataParameterTypes, + parameters: actionRequest.parameters as TParameters, }, }, user: { diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/mocks.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/mocks.ts index dac3a5c8f1ddb..f34302ecf8b74 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/mocks.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/mocks.ts @@ -17,6 +17,7 @@ import { import type { ActionsClientMock } from '@kbn/actions-plugin/server/actions_client/actions_client.mock'; import type { ConnectorWithExtraFindData } from '@kbn/actions-plugin/server/application/connector/types'; import { merge } from 'lodash'; +import { SentinelOneDataGenerator } from '../../../../../../common/endpoint/data_generators/sentinelone_data_generator'; import type { NormalizedExternalConnectorClient } from '../../..'; import type { ResponseActionsClientOptionsMock } from '../mocks'; import { responseActionsClientMock } from '../mocks'; @@ -288,6 +289,13 @@ const createConnectorActionsClientMock = (): ActionsClientMock => { }, }); + case SUB_ACTION.GET_REMOTE_SCRIPT_STATUS: + return responseActionsClientMock.createConnectorActionExecuteResponse({ + data: new SentinelOneDataGenerator( + 'seed' + ).generateSentinelOneApiRemoteScriptStatusResponse({ status: 'completed' }), + }); + default: return responseActionsClientMock.createConnectorActionExecuteResponse(); } diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/sentinel_one_actions_client.test.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/sentinel_one_actions_client.test.ts index 6a5304f17b82e..5564d28849654 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/sentinel_one_actions_client.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/sentinel_one_actions_client.test.ts @@ -35,15 +35,25 @@ import type { ResponseActionGetFileParameters, SentinelOneGetFileRequestMeta, KillOrSuspendProcessRequestBody, + KillProcessActionOutputContent, + ResponseActionParametersWithProcessName, + SentinelOneKillProcessRequestMeta, } from '../../../../../../common/endpoint/types'; import type { SearchHit, SearchResponse } from '@elastic/elasticsearch/lib/api/types'; -import type { ResponseActionGetFileRequestBody } from '../../../../../../common/api/endpoint'; +import type { + ResponseActionGetFileRequestBody, + GetProcessesRequestBody, +} from '../../../../../../common/api/endpoint'; import { SUB_ACTION } from '@kbn/stack-connectors-plugin/common/sentinelone/constants'; import { ACTIONS_SEARCH_PAGE_SIZE } from '../../constants'; import type { ElasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; import { Readable } from 'stream'; import { RESPONSE_ACTIONS_ZIP_PASSCODE } from '../../../../../../common/endpoint/service/response_actions/constants'; import type { DeeplyMockedKeys } from '@kbn/utility-types-jest'; +import type { + SentinelOneGetRemoteScriptStatusApiResponse, + SentinelOneRemoteScriptExecutionStatus, +} from '@kbn/stack-connectors-plugin/common/sentinelone/types'; jest.mock('../../action_details_by_id', () => { const originalMod = jest.requireActual('../../action_details_by_id'); @@ -75,14 +85,15 @@ describe('SentinelOneActionsClient class', () => { s1ActionsClient = new SentinelOneActionsClient(classConstructorOptions); }); - it.each(['suspendProcess', 'runningProcesses', 'execute', 'upload', 'scan'] as Array< - keyof ResponseActionsClient - >)('should throw an un-supported error for %s', async (methodName) => { - // @ts-expect-error Purposely passing in empty object for options - await expect(s1ActionsClient[methodName]({})).rejects.toBeInstanceOf( - ResponseActionsNotSupportedError - ); - }); + it.each(['suspendProcess', 'execute', 'upload', 'scan'] as Array)( + 'should throw an un-supported error for %s', + async (methodName) => { + // @ts-expect-error Purposely passing in empty object for options + await expect(s1ActionsClient[methodName]({})).rejects.toBeInstanceOf( + ResponseActionsNotSupportedError + ); + } + ); it('should error if multiple agent ids are received', async () => { const payload = createS1IsolationOptions(); @@ -734,6 +745,174 @@ describe('SentinelOneActionsClient class', () => { }); }); }); + + describe('for kill-process response action', () => { + let actionRequestsSearchResponse: SearchResponse< + LogsEndpointAction< + ResponseActionParametersWithProcessName, + KillProcessActionOutputContent, + SentinelOneKillProcessRequestMeta + > + >; + + const setGetRemoteScriptStatusConnectorResponse = ( + response: SentinelOneGetRemoteScriptStatusApiResponse + ): void => { + const executeMockFn = (connectorActionsMock.execute as jest.Mock).getMockImplementation(); + + (connectorActionsMock.execute as jest.Mock).mockImplementation(async (options) => { + if (options.params.subAction === SUB_ACTION.GET_REMOTE_SCRIPT_STATUS) { + return responseActionsClientMock.createConnectorActionExecuteResponse({ + data: response, + }); + } + + return executeMockFn!(options); + }); + }; + + beforeEach(() => { + const s1DataGenerator = new SentinelOneDataGenerator('seed'); + actionRequestsSearchResponse = s1DataGenerator.toEsSearchResponse([ + s1DataGenerator.generateActionEsHit< + ResponseActionParametersWithProcessName, + KillProcessActionOutputContent, + SentinelOneKillProcessRequestMeta + >({ + agent: { id: 'agent-uuid-1' }, + EndpointActions: { + data: { command: 'kill-process', parameters: { process_name: 'foo' } }, + }, + meta: { + agentId: 's1-agent-a', + agentUUID: 'agent-uuid-1', + hostName: 's1-host-name', + parentTaskId: 's1-parent-task-123', + }, + }), + ]); + const actionResponsesSearchResponse = s1DataGenerator.toEsSearchResponse< + LogsEndpointActionResponse | EndpointActionResponse + >([]); + + applyEsClientSearchMock({ + esClientMock: classConstructorOptions.esClient, + index: ENDPOINT_ACTIONS_INDEX, + response: actionRequestsSearchResponse, + pitUsage: true, + }); + + applyEsClientSearchMock({ + esClientMock: classConstructorOptions.esClient, + index: ENDPOINT_ACTION_RESPONSES_INDEX_PATTERN, + response: actionResponsesSearchResponse, + }); + }); + + it('should create response at error if request has no parentTaskId', async () => { + actionRequestsSearchResponse.hits.hits[0]!._source!.meta!.parentTaskId = ''; + await s1ActionsClient.processPendingActions(processPendingActionsOptions); + + expect(processPendingActionsOptions.addToQueue).toHaveBeenCalledWith({ + '@timestamp': expect.any(String), + EndpointActions: { + action_id: '1d6e6796-b0af-496f-92b0-25fcb06db499', + completed_at: expect.any(String), + data: { + command: 'kill-process', + comment: '', + }, + input_type: 'sentinel_one', + started_at: expect.any(String), + }, + agent: { + id: 'agent-uuid-1', + }, + error: { + message: + "Action request missing SentinelOne 'parentTaskId' value - unable check on its status", + }, + meta: undefined, + }); + }); + + it('should do nothing if action is still pending', async () => { + setGetRemoteScriptStatusConnectorResponse( + new SentinelOneDataGenerator('seed').generateSentinelOneApiRemoteScriptStatusResponse({ + status: 'pending', + }) + ); + await s1ActionsClient.processPendingActions(processPendingActionsOptions); + + expect(processPendingActionsOptions.addToQueue).not.toHaveBeenCalled(); + }); + + it.each` + s1ScriptStatus | expectedResponseActionResponse + ${'canceled'} | ${'failure'} + ${'expired'} | ${'failure'} + ${'failed'} | ${'failure'} + ${'completed'} | ${'success'} + `( + 'should create $expectedResponseActionResponse response when S1 script status is $s1ScriptStatus', + async ({ s1ScriptStatus, expectedResponseActionResponse }) => { + const s1ScriptStatusResponse = new SentinelOneDataGenerator( + 'seed' + ).generateSentinelOneApiRemoteScriptStatusResponse({ + status: s1ScriptStatus, + }); + setGetRemoteScriptStatusConnectorResponse(s1ScriptStatusResponse); + await s1ActionsClient.processPendingActions(processPendingActionsOptions); + + if (expectedResponseActionResponse === 'failure') { + expect(processPendingActionsOptions.addToQueue).toHaveBeenCalledWith( + expect.objectContaining({ + error: { + message: expect.any(String), + }, + }) + ); + } else { + expect(processPendingActionsOptions.addToQueue).toHaveBeenCalledWith( + expect.objectContaining({ + meta: { taskId: s1ScriptStatusResponse.data[0].id }, + error: undefined, + EndpointActions: expect.objectContaining({ + data: expect.objectContaining({ + output: { + type: 'json', + content: { + code: 'ok', + command: 'kill-process', + process_name: 'foo', + }, + }, + }), + }), + }) + ); + } + } + ); + + it.each([ + 'created', + 'pending', + 'pending_user_action', + 'scheduled', + 'in_progress', + 'partially_completed', + ])('should leave action pending when S1 script status is %s', async (s1ScriptStatus) => { + setGetRemoteScriptStatusConnectorResponse( + new SentinelOneDataGenerator('seed').generateSentinelOneApiRemoteScriptStatusResponse({ + status: s1ScriptStatus as SentinelOneRemoteScriptExecutionStatus['status'], + }) + ); + await s1ActionsClient.processPendingActions(processPendingActionsOptions); + + expect(processPendingActionsOptions.addToQueue).not.toHaveBeenCalled(); + }); + }); }); describe('#getFile()', () => { @@ -1294,4 +1473,163 @@ describe('SentinelOneActionsClient class', () => { expect(classConstructorOptions.casesClient?.attachments.bulkCreate).toHaveBeenCalled(); }); }); + + describe('#runningProcesses()', () => { + let processesActionRequest: GetProcessesRequestBody; + + beforeEach(() => { + // @ts-expect-error readonly prop assignment + classConstructorOptions.endpointService.experimentalFeatures.responseActionsSentinelOneProcessesEnabled = + true; + + processesActionRequest = responseActionsClientMock.createRunningProcessesOptions(); + }); + + it('should error if feature flag is disabled', async () => { + // @ts-expect-error readonly prop assignment + classConstructorOptions.endpointService.experimentalFeatures.responseActionsSentinelOneProcessesEnabled = + false; + + await expect(s1ActionsClient.runningProcesses(processesActionRequest)).rejects.toThrow( + `processes not supported for sentinel_one agent type. Feature disabled` + ); + }); + + it('should error if host is running Windows', async () => { + connectorActionsMock.execute.mockResolvedValue( + responseActionsClientMock.createConnectorActionExecuteResponse({ + data: sentinelOneMock.createGetAgentsResponse([ + sentinelOneMock.createSentinelOneAgentDetails({ osType: 'windows' }), + ]), + }) + ); + + await expect(s1ActionsClient.runningProcesses(processesActionRequest)).rejects.toThrow( + 'Retrieval of running processes for Windows host is not supported by SentinelOne' + ); + }); + + it('should retrieve script execution information from S1 using host OS', async () => { + await s1ActionsClient.runningProcesses(processesActionRequest); + + expect(connectorActionsMock.execute).toHaveBeenCalledWith({ + params: { + subAction: 'getRemoteScripts', + subActionParams: { + osTypes: 'linux', + query: 'process list', + scriptType: 'dataCollection', + }, + }, + }); + }); + + it('should error if unable to get S1 script information', async () => { + const executeMockImplementation = connectorActionsMock.execute.getMockImplementation()!; + connectorActionsMock.execute.mockImplementation(async (options) => { + if (options.params.subAction === SUB_ACTION.GET_REMOTE_SCRIPTS) { + return responseActionsClientMock.createConnectorActionExecuteResponse({ + data: { data: [] }, + }); + } + return executeMockImplementation.call(connectorActionsMock, options); + }); + + await expect(s1ActionsClient.runningProcesses(processesActionRequest)).rejects.toThrow( + 'Unable to find a script from SentinelOne to handle [running-processes] response action for host running [linux])' + ); + }); + + it('should send execute script request to S1 for process list', async () => { + await s1ActionsClient.runningProcesses(processesActionRequest); + + expect(connectorActionsMock.execute).toHaveBeenCalledWith({ + params: { + subAction: 'executeScript', + subActionParams: { + filter: { uuids: '1-2-3' }, + script: { + inputParams: '', + outputDestination: 'SentinelCloud', + requiresApproval: false, + scriptId: '1466645476786791838', + taskDescription: expect.stringContaining( + 'Action triggered from Elastic Security by user [foo] for action [running-processes' + ), + }, + }, + }, + }); + }); + + it('should return action details on success', async () => { + await s1ActionsClient.runningProcesses(processesActionRequest); + + expect(getActionDetailsByIdMock).toHaveBeenCalled(); + }); + + it('should create action request doc with expected meta info', async () => { + await s1ActionsClient.runningProcesses(processesActionRequest); + + expect(classConstructorOptions.esClient.index).toHaveBeenCalledWith( + { + document: { + '@timestamp': expect.any(String), + EndpointActions: { + action_id: expect.any(String), + data: { + command: 'running-processes', + comment: 'test comment', + hosts: { '1-2-3': { name: 'sentinelone-1460' } }, + parameters: undefined, + }, + expiration: expect.any(String), + input_type: 'sentinel_one', + type: 'INPUT_ACTION', + }, + agent: { id: ['1-2-3'] }, + meta: { + agentId: '1845174760470303882', + agentUUID: '1-2-3', + hostName: 'sentinelone-1460', + parentTaskId: 'task-789', + }, + user: { id: 'foo' }, + }, + index: '.logs-endpoint.actions-default', + refresh: 'wait_for', + }, + { meta: true } + ); + }); + + it('should update cases', async () => { + processesActionRequest = { + ...processesActionRequest, + case_ids: ['case-1'], + }; + await s1ActionsClient.runningProcesses(processesActionRequest); + + expect(classConstructorOptions.casesClient?.attachments.bulkCreate).toHaveBeenCalled(); + }); + + it('should still create action request when running in automated mode', async () => { + classConstructorOptions.isAutomated = true; + classConstructorOptions.connectorActions = + responseActionsClientMock.createNormalizedExternalConnectorClient( + sentinelOneMock.createConnectorActionsClient() + ); + s1ActionsClient = new SentinelOneActionsClient(classConstructorOptions); + await s1ActionsClient.runningProcesses(processesActionRequest); + + expect(classConstructorOptions.esClient.index).toHaveBeenCalledWith( + expect.objectContaining({ + document: expect.objectContaining({ + error: { message: 'Action [running-processes] not supported' }, + }), + }), + { meta: true } + ); + }); + }); }); diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/sentinel_one_actions_client.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/sentinel_one_actions_client.ts index 54d2147cbe2e2..fe0eb043e2b9e 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/sentinel_one_actions_client.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/sentinel_one_actions_client.ts @@ -19,6 +19,8 @@ import type { SentinelOneGetRemoteScriptsParams, SentinelOneGetRemoteScriptsResponse, SentinelOneExecuteScriptResponse, + SentinelOneRemoteScriptExecutionStatus, + SentinelOneGetRemoteScriptStatusApiResponse, } from '@kbn/stack-connectors-plugin/common/sentinelone/types'; import type { QueryDslQueryContainer, @@ -27,7 +29,11 @@ import type { } from '@elastic/elasticsearch/lib/api/types'; import type { Readable } from 'stream'; import type { Mutable } from 'utility-types'; -import type { SentinelOneKillProcessScriptArgs, SentinelOneScriptArgs } from './types'; +import type { + SentinelOneKillProcessScriptArgs, + SentinelOneScriptArgs, + SentinelOneProcessListScriptArgs, +} from './types'; import { ACTIONS_SEARCH_PAGE_SIZE } from '../../constants'; import type { NormalizedExternalConnectorClient } from '../lib/normalized_external_connector_client'; import { SENTINEL_ONE_ACTIVITY_INDEX_PATTERN } from '../../../../../../common'; @@ -65,8 +71,12 @@ import type { SentinelOneKillProcessRequestMeta, UploadedFileInfo, ResponseActionParametersWithProcessName, + GetProcessesActionOutputContent, + SentinelOneProcessesRequestMeta, + SentinelOneKillProcessResponseMeta, } from '../../../../../../common/endpoint/types'; import type { + GetProcessesRequestBody, IsolationRouteRequestBody, ResponseActionGetFileRequestBody, } from '../../../../../../common/api/endpoint'; @@ -663,6 +673,80 @@ export class SentinelOneActionsClient extends ResponseActionsClientImpl { return actionDetails; } + public async runningProcesses( + actionRequest: GetProcessesRequestBody, + options?: CommonResponseActionMethodOptions + ): Promise> { + if ( + !this.options.endpointService.experimentalFeatures.responseActionsSentinelOneProcessesEnabled + ) { + throw new ResponseActionsClientError( + `processes not supported for ${this.agentType} agent type. Feature disabled`, + 400 + ); + } + + const reqIndexOptions: ResponseActionsClientWriteActionRequestToEndpointIndexOptions< + undefined, + GetProcessesActionOutputContent, + Partial + > = { + ...actionRequest, + ...this.getMethodOptions(options), + command: 'running-processes', + meta: { parentTaskId: '' }, + }; + + if (!reqIndexOptions.error) { + let error = (await this.validateRequest(reqIndexOptions)).error; + + if (!error) { + const s1AgentDetails = await this.getAgentDetails(reqIndexOptions.endpoint_ids[0]); + const processesScriptInfo = await this.fetchScriptInfo( + 'running-processes', + s1AgentDetails.osType + ); + + try { + const s1Response = await this.sendAction( + SUB_ACTION.EXECUTE_SCRIPT, + { + filter: { + uuids: actionRequest.endpoint_ids[0], + }, + script: { + scriptId: processesScriptInfo.scriptId, + taskDescription: this.buildExternalComment(reqIndexOptions), + requiresApproval: false, + outputDestination: 'SentinelCloud', + inputParams: processesScriptInfo.buildScriptArgs({}), + }, + } + ); + + reqIndexOptions.meta = { + parentTaskId: s1Response.data?.data?.parentTaskId ?? '', + }; + } catch (err) { + error = err; + } + } + + reqIndexOptions.error = error?.message; + + if (!this.options.isAutomated && error) { + throw error; + } + } + + const { actionDetails } = await this.handleResponseActionCreation< + undefined, + GetProcessesActionOutputContent + >(reqIndexOptions); + + return actionDetails; + } + async processPendingActions({ abortSignal, addToQueue, @@ -670,7 +754,6 @@ export class SentinelOneActionsClient extends ResponseActionsClientImpl { if (abortSignal.aborted) { return; } - for await (const pendingActions of this.fetchAllPendingActions()) { if (abortSignal.aborted) { return; @@ -715,6 +798,23 @@ export class SentinelOneActionsClient extends ResponseActionsClientImpl { } } break; + + case 'kill-process': + { + const responseDocsForKillProcess = await this.checkPendingKillProcessActions( + typePendingActions as Array< + ResponseActionsClientPendingAction< + ResponseActionParametersWithProcessName, + KillProcessActionOutputContent, + SentinelOneKillProcessRequestMeta + > + > + ); + if (responseDocsForKillProcess.length) { + addToQueue(...responseDocsForKillProcess); + } + } + break; } } } @@ -729,14 +829,15 @@ export class SentinelOneActionsClient extends ResponseActionsClientImpl { private async fetchScriptInfo< TScriptOptions extends SentinelOneScriptArgs = SentinelOneScriptArgs >( - scriptType: Extract, + scriptType: Extract, osType: string | 'linux' | 'macos' | 'windows' ): Promise> { const searchQueryParams: Mutable> = { query: '', osTypes: osType, }; - let buildScriptArgs = NOOP_THROW as FetchScriptInfoResponse['buildScriptArgs']; + let buildScriptArgs: FetchScriptInfoResponse['buildScriptArgs'] = + NOOP_THROW as FetchScriptInfoResponse['buildScriptArgs']; let isDesiredScript: ( scriptInfo: SentinelOneGetRemoteScriptsResponse['data'][number] ) => boolean = () => false; @@ -746,7 +847,6 @@ export class SentinelOneActionsClient extends ResponseActionsClientImpl { case 'kill-process': searchQueryParams.query = 'terminate'; searchQueryParams.scriptType = 'action'; - isDesiredScript = (scriptInfo) => { return ( scriptInfo.creator === 'SentinelOne' && @@ -758,6 +858,22 @@ export class SentinelOneActionsClient extends ResponseActionsClientImpl { }; break; + case 'running-processes': + if (osType === 'windows') { + throw new ResponseActionsClientError( + `Retrieval of running processes for Windows host is not supported by SentinelOne`, + 405 + ); + } + + searchQueryParams.query = 'process list'; + searchQueryParams.scriptType = 'dataCollection'; + isDesiredScript = (scriptInfo) => { + return scriptInfo.creator === 'SentinelOne' && scriptInfo.creatorId === '-1'; + }; + + break; + default: throw new ResponseActionsClientError( `Unable to fetch SentinelOne script for OS [${osType}]. Unknown script type [${scriptType}]` @@ -780,9 +896,10 @@ export class SentinelOneActionsClient extends ResponseActionsClientImpl { ); } + // Define the `buildScriptArgs` callback for the Script type switch (scriptType) { case 'kill-process': - buildScriptArgs = (args: SentinelOneKillProcessScriptArgs) => { + buildScriptArgs = ((args: SentinelOneKillProcessScriptArgs) => { if (!args.processName) { throw new ResponseActionsClientError( `'processName' missing while building script args for [${s1Script.scriptName} (id: ${s1Script.id})] script` @@ -795,8 +912,12 @@ export class SentinelOneActionsClient extends ResponseActionsClientImpl { // Linux + Macos return `--terminate --processes "${args.processName}" --force`; - }; + }) as FetchScriptInfoResponse['buildScriptArgs']; + + break; + case 'running-processes': + buildScriptArgs = () => ''; break; } @@ -1220,4 +1341,175 @@ export class SentinelOneActionsClient extends ResponseActionsClientImpl { return completedResponses; } + + /** + * Calculates the state of a SentinelOne Task using the response from their task status API. It + * returns a normalized object with basic info derived from the task status value + * @param taskStatusRecord + * @private + */ + private calculateTaskState(taskStatusRecord: SentinelOneRemoteScriptExecutionStatus): { + isPending: boolean; + isError: boolean; + message: string; + } { + const taskStatusValue = taskStatusRecord.status; + let message = + taskStatusRecord.detailedStatus ?? taskStatusRecord.statusDescription ?? taskStatusValue; + let isPending: boolean; + let isError: boolean; + + switch (taskStatusValue) { + // PENDING STATUSES ------------------------------------------ + case 'created': + case 'pending': + case 'pending_user_action': + case 'scheduled': + case 'in_progress': + case 'partially_completed': + isPending = true; + isError = true; + break; + + // COMPLETE STATUSES ------------------------------------------ + case 'canceled': + isPending = false; + isError = true; + message = `SentinelOne Parent Task Id [${taskStatusRecord.parentTaskId}] was canceled${ + taskStatusRecord.detailedStatus ? ` - ${taskStatusRecord.detailedStatus}` : '' + }`; + break; + + case 'completed': + isPending = false; + isError = false; + break; + + case 'expired': + isPending = false; + isError = true; + break; + + case 'failed': + isPending = false; + isError = true; + break; + + default: + isPending = false; + isError = true; + message = `Unable to determine task state - unknown SentinelOne task status value [${taskStatusRecord}] for task parent id [${taskStatusRecord.parentTaskId}]`; + } + + return { + isPending, + isError, + message, + }; + } + + private async checkPendingKillProcessActions( + actionRequests: Array< + ResponseActionsClientPendingAction< + ResponseActionParametersWithProcessName, + KillProcessActionOutputContent, + SentinelOneKillProcessRequestMeta + > + > + ): Promise { + const warnings: string[] = []; + const completedResponses: LogsEndpointActionResponse[] = []; + + for (const pendingAction of actionRequests) { + const actionRequest = pendingAction.action; + const s1ParentTaskId = actionRequest.meta?.parentTaskId; + + if (!s1ParentTaskId) { + completedResponses.push( + this.buildActionResponseEsDoc< + KillProcessActionOutputContent, + SentinelOneKillProcessResponseMeta + >({ + actionId: actionRequest.EndpointActions.action_id, + agentId: Array.isArray(actionRequest.agent.id) + ? actionRequest.agent.id[0] + : actionRequest.agent.id, + data: { + command: 'kill-process', + comment: '', + }, + error: { + message: `Action request missing SentinelOne 'parentTaskId' value - unable check on its status`, + }, + }) + ); + + warnings.push( + `Response Action [${actionRequest.EndpointActions.action_id}] is missing [meta.parentTaskId]! (should not have happened)` + ); + } else { + const s1TaskStatusApiResponse = + await this.sendAction( + SUB_ACTION.GET_REMOTE_SCRIPT_STATUS, + { parentTaskId: s1ParentTaskId } + ); + + if (s1TaskStatusApiResponse.data?.data.length) { + const killProcessStatus = s1TaskStatusApiResponse.data.data[0]; + const taskState = this.calculateTaskState(killProcessStatus); + + if (!taskState.isPending) { + this.log.debug(`Action is completed - generating response doc for it`); + + const error: LogsEndpointActionResponse['error'] = taskState.isError + ? { + message: `Action failed to execute in SentinelOne. message: ${taskState.message}`, + } + : undefined; + + completedResponses.push( + this.buildActionResponseEsDoc< + KillProcessActionOutputContent, + SentinelOneKillProcessResponseMeta + >({ + actionId: actionRequest.EndpointActions.action_id, + agentId: Array.isArray(actionRequest.agent.id) + ? actionRequest.agent.id[0] + : actionRequest.agent.id, + data: { + command: 'kill-process', + comment: taskState.message, + output: { + type: 'json', + content: { + code: killProcessStatus.statusCode ?? killProcessStatus.status, + command: actionRequest.EndpointActions.data.command, + process_name: actionRequest.EndpointActions.data.parameters?.process_name, + }, + }, + }, + error, + meta: { + taskId: killProcessStatus.id, + }, + }) + ); + } + } + } + } + + this.log.debug( + () => + `${completedResponses.length} kill-process action responses generated:\n${stringify( + completedResponses + )}` + ); + + if (warnings.length > 0) { + this.log.warn(warnings.join('\n')); + } + + return completedResponses; + } } diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/types.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/types.ts index a51a9ec981765..e3841d5a50a08 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/types.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/types.ts @@ -9,7 +9,11 @@ export interface SentinelOneKillProcessScriptArgs { processName: string; } +export type SentinelOneProcessListScriptArgs = Record; + /** * All the possible set of arguments running SentinelOne scripts that we support for response actions */ -export type SentinelOneScriptArgs = SentinelOneKillProcessScriptArgs; +export type SentinelOneScriptArgs = + | SentinelOneKillProcessScriptArgs + | SentinelOneProcessListScriptArgs; diff --git a/x-pack/plugins/security_solution/server/integration_tests/telemetry.test.ts b/x-pack/plugins/security_solution/server/integration_tests/telemetry.test.ts index fd91986cb30e5..36284722cbf59 100644 --- a/x-pack/plugins/security_solution/server/integration_tests/telemetry.test.ts +++ b/x-pack/plugins/security_solution/server/integration_tests/telemetry.test.ts @@ -148,7 +148,8 @@ describe('telemetry tasks', () => { }); }); - describe('detection-rules', () => { + // FLAKY: https://github.com/elastic/kibana/issues/187719 + describe.skip('detection-rules', () => { it('should execute when scheduled', async () => { await mockAndScheduleDetectionRulesTask(); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/index.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/index.ts index f2ffb98ad5432..b7c0a1143f1a7 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/index.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/index.ts @@ -9,3 +9,4 @@ export { numberDiffAlgorithm } from './number_diff_algorithm'; export { singleLineStringDiffAlgorithm } from './single_line_string_diff_algorithm'; export { scalarArrayDiffAlgorithm } from './scalar_array_diff_algorithm'; export { simpleDiffAlgorithm } from './simple_diff_algorithm'; +export { multiLineStringDiffAlgorithm } from './multi_line_string_diff_algorithm'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/multi_line_string_diff_algorithm.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/multi_line_string_diff_algorithm.test.ts new file mode 100644 index 0000000000000..bd0459be914c7 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/multi_line_string_diff_algorithm.test.ts @@ -0,0 +1,174 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ThreeVersionsOf } from '../../../../../../../../common/api/detection_engine'; +import { + ThreeWayDiffOutcome, + ThreeWayMergeOutcome, + MissingVersion, +} from '../../../../../../../../common/api/detection_engine'; +import { multiLineStringDiffAlgorithm } from './multi_line_string_diff_algorithm'; + +describe('multiLineStringDiffAlgorithm', () => { + it('returns current_version as merged output if there is no update - scenario AAA', () => { + const mockVersions: ThreeVersionsOf = { + base_version: 'My description.\nThis is a second line.', + current_version: 'My description.\nThis is a second line.', + target_version: 'My description.\nThis is a second line.', + }; + + const result = multiLineStringDiffAlgorithm(mockVersions); + + expect(result).toEqual( + expect.objectContaining({ + merged_version: mockVersions.current_version, + diff_outcome: ThreeWayDiffOutcome.StockValueNoUpdate, + merge_outcome: ThreeWayMergeOutcome.Current, + has_conflict: false, + }) + ); + }); + + it('returns current_version as merged output if current_version is different and there is no update - scenario ABA', () => { + const mockVersions: ThreeVersionsOf = { + base_version: 'My description.\nThis is a second line.', + current_version: 'My GREAT description.\nThis is a second line.', + target_version: 'My description.\nThis is a second line.', + }; + + const result = multiLineStringDiffAlgorithm(mockVersions); + + expect(result).toEqual( + expect.objectContaining({ + merged_version: mockVersions.current_version, + diff_outcome: ThreeWayDiffOutcome.CustomizedValueNoUpdate, + merge_outcome: ThreeWayMergeOutcome.Current, + has_conflict: false, + }) + ); + }); + + it('returns target_version as merged output if current_version is the same and there is an update - scenario AAB', () => { + const mockVersions: ThreeVersionsOf = { + base_version: 'My description.\nThis is a second line.', + current_version: 'My description.\nThis is a second line.', + target_version: 'My GREAT description.\nThis is a second line.', + }; + + const result = multiLineStringDiffAlgorithm(mockVersions); + + expect(result).toEqual( + expect.objectContaining({ + merged_version: mockVersions.target_version, + diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + has_conflict: false, + }) + ); + }); + + it('returns current_version as merged output if current version is different but it matches the update - scenario ABB', () => { + const mockVersions: ThreeVersionsOf = { + base_version: 'My description.\nThis is a second line.', + current_version: 'My GREAT description.\nThis is a second line.', + target_version: 'My GREAT description.\nThis is a second line.', + }; + + const result = multiLineStringDiffAlgorithm(mockVersions); + + expect(result).toEqual( + expect.objectContaining({ + merged_version: mockVersions.current_version, + diff_outcome: ThreeWayDiffOutcome.CustomizedValueSameUpdate, + merge_outcome: ThreeWayMergeOutcome.Current, + has_conflict: false, + }) + ); + }); + + describe('if all three versions are different - scenario ABC', () => { + it('returns a computated merged version without a conflict if 3 way merge is possible', () => { + const mockVersions: ThreeVersionsOf = { + base_version: `My description.\f\nThis is a second\u2001 line.\f\nThis is a third line.`, + current_version: `My GREAT description.\f\nThis is a second\u2001 line.\f\nThis is a third line.`, + target_version: `My description.\f\nThis is a second\u2001 line.\f\nThis is a GREAT line.`, + }; + + const expectedMergedVersion = `My GREAT description.\f\nThis is a second\u2001 line.\f\nThis is a GREAT line.`; + + const result = multiLineStringDiffAlgorithm(mockVersions); + + expect(result).toEqual( + expect.objectContaining({ + merged_version: expectedMergedVersion, + diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Merged, + has_conflict: false, + }) + ); + }); + + it('returns the current_version with a conflict if 3 way merge is not possible', () => { + const mockVersions: ThreeVersionsOf = { + base_version: 'My description.\nThis is a second line.', + current_version: 'My GREAT description.\nThis is a third line.', + target_version: 'My EXCELLENT description.\nThis is a fourth.', + }; + + const result = multiLineStringDiffAlgorithm(mockVersions); + + expect(result).toEqual( + expect.objectContaining({ + merged_version: mockVersions.current_version, + diff_outcome: ThreeWayDiffOutcome.CustomizedValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Conflict, + has_conflict: true, + }) + ); + }); + }); + + describe('if base_version is missing', () => { + it('returns current_version as merged output if current_version and target_version are the same - scenario -AA', () => { + const mockVersions: ThreeVersionsOf = { + base_version: MissingVersion, + current_version: 'My description.\nThis is a second line.', + target_version: 'My description.\nThis is a second line.', + }; + + const result = multiLineStringDiffAlgorithm(mockVersions); + + expect(result).toEqual( + expect.objectContaining({ + merged_version: mockVersions.current_version, + diff_outcome: ThreeWayDiffOutcome.StockValueNoUpdate, + merge_outcome: ThreeWayMergeOutcome.Current, + has_conflict: false, + }) + ); + }); + + it('returns target_version as merged output if current_version and target_version are different - scenario -AB', () => { + const mockVersions: ThreeVersionsOf = { + base_version: MissingVersion, + current_version: `My GREAT description.\nThis is a second line.`, + target_version: `My description.\nThis is a second line, now longer.`, + }; + + const result = multiLineStringDiffAlgorithm(mockVersions); + + expect(result).toEqual( + expect.objectContaining({ + merged_version: mockVersions.target_version, + diff_outcome: ThreeWayDiffOutcome.StockValueCanUpdate, + merge_outcome: ThreeWayMergeOutcome.Target, + has_conflict: false, + }) + ); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/multi_line_string_diff_algorithm.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/multi_line_string_diff_algorithm.ts new file mode 100644 index 0000000000000..aa3b3c6b39f43 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/multi_line_string_diff_algorithm.ts @@ -0,0 +1,114 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { merge } from 'node-diff3'; +import { assertUnreachable } from '../../../../../../../../common/utility_types'; +import type { + ThreeVersionsOf, + ThreeWayDiff, +} from '../../../../../../../../common/api/detection_engine/prebuilt_rules'; +import { + determineDiffOutcome, + determineIfValueCanUpdate, + ThreeWayDiffOutcome, + ThreeWayMergeOutcome, + MissingVersion, +} from '../../../../../../../../common/api/detection_engine/prebuilt_rules'; + +/** + * Diff algorithm used for string fields that contain multiple lines + */ +export const multiLineStringDiffAlgorithm = ( + versions: ThreeVersionsOf +): ThreeWayDiff => { + const { + base_version: baseVersion, + current_version: currentVersion, + target_version: targetVersion, + } = versions; + + const diffOutcome = determineDiffOutcome(baseVersion, currentVersion, targetVersion); + const valueCanUpdate = determineIfValueCanUpdate(diffOutcome); + + const { mergeOutcome, mergedVersion } = mergeVersions({ + baseVersion, + currentVersion, + targetVersion, + diffOutcome, + }); + + return { + base_version: baseVersion, + current_version: currentVersion, + target_version: targetVersion, + merged_version: mergedVersion, + + diff_outcome: diffOutcome, + merge_outcome: mergeOutcome, + has_update: valueCanUpdate, + has_conflict: mergeOutcome === ThreeWayMergeOutcome.Conflict, + }; +}; + +interface MergeResult { + mergeOutcome: ThreeWayMergeOutcome; + mergedVersion: string; +} + +interface MergeArgs { + baseVersion: string | MissingVersion; + currentVersion: string; + targetVersion: string; + diffOutcome: ThreeWayDiffOutcome; +} + +const mergeVersions = ({ + baseVersion, + currentVersion, + targetVersion, + diffOutcome, +}: MergeArgs): MergeResult => { + switch (diffOutcome) { + case ThreeWayDiffOutcome.StockValueNoUpdate: + case ThreeWayDiffOutcome.CustomizedValueNoUpdate: + case ThreeWayDiffOutcome.CustomizedValueSameUpdate: { + return { + mergeOutcome: ThreeWayMergeOutcome.Current, + mergedVersion: currentVersion, + }; + } + case ThreeWayDiffOutcome.StockValueCanUpdate: { + return { + mergeOutcome: ThreeWayMergeOutcome.Target, + mergedVersion: targetVersion, + }; + } + case ThreeWayDiffOutcome.CustomizedValueCanUpdate: { + if (baseVersion === MissingVersion) { + return { + mergeOutcome: ThreeWayMergeOutcome.Conflict, + mergedVersion: currentVersion, + }; + } + const mergedVersion = merge(currentVersion, baseVersion, targetVersion, { + stringSeparator: /(\S+|\s+)/g, // Retains all whitespace, which we keep to preserve formatting + }); + + return mergedVersion.conflict + ? { + mergeOutcome: ThreeWayMergeOutcome.Conflict, + mergedVersion: currentVersion, + } + : { + mergeOutcome: ThreeWayMergeOutcome.Merged, + mergedVersion: mergedVersion.result.join(''), + }; + } + default: + return assertUnreachable(diffOutcome); + } +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/create_security_rule_type_wrapper.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/create_security_rule_type_wrapper.ts index 471087fa77a4a..81685984439cd 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/create_security_rule_type_wrapper.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/create_security_rule_type_wrapper.ts @@ -189,9 +189,9 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper = }); let result = createResultObject(state); - let wroteWarningStatus = false; - let warningMessage; - let hasError = false; + + const wrapperWarnings = []; + const wrapperErrors = []; const primaryTimestamp = timestampOverride ?? TIMESTAMP; const secondaryTimestamp = @@ -262,59 +262,54 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper = if (!isMachineLearningParams(params)) { const privileges = await checkPrivilegesFromEsClient(esClient, inputIndex); - const { wroteWarningMessage, warningStatusMessage: readIndexWarningMessage } = - await hasReadIndexPrivileges({ - privileges, - ruleExecutionLogger, - uiSettingsClient, - }); + const readIndexWarningMessage = await hasReadIndexPrivileges({ + privileges, + ruleExecutionLogger, + uiSettingsClient, + }); - wroteWarningStatus = wroteWarningMessage; - warningMessage = readIndexWarningMessage; - - if (!wroteWarningStatus) { - const timestampFieldCaps = await withSecuritySpan('fieldCaps', () => - services.scopedClusterClient.asCurrentUser.fieldCaps( - { - index: inputIndex, - fields: secondaryTimestamp - ? [primaryTimestamp, secondaryTimestamp] - : [primaryTimestamp], - include_unmapped: true, - runtime_mappings: runtimeMappings, - ignore_unavailable: true, - }, - { meta: true } - ) - ); - - const { - wroteWarningStatus: wroteWarningStatusResult, - foundNoIndices, - warningMessage: warningMissingTimestampFieldsMessage, - } = await hasTimestampFields({ + if (readIndexWarningMessage != null) { + wrapperWarnings.push(readIndexWarningMessage); + } + + const timestampFieldCaps = await withSecuritySpan('fieldCaps', () => + services.scopedClusterClient.asCurrentUser.fieldCaps( + { + index: inputIndex, + fields: secondaryTimestamp + ? [primaryTimestamp, secondaryTimestamp] + : [primaryTimestamp], + include_unmapped: true, + runtime_mappings: runtimeMappings, + ignore_unavailable: true, + }, + { meta: true } + ) + ); + + const { foundNoIndices, warningMessage: warningMissingTimestampFieldsMessage } = + await hasTimestampFields({ timestampField: primaryTimestamp, timestampFieldCapsResponse: timestampFieldCaps, inputIndices: inputIndex, ruleExecutionLogger, }); - wroteWarningStatus = wroteWarningStatusResult; - warningMessage = warningMissingTimestampFieldsMessage; - skipExecution = foundNoIndices; + if (warningMissingTimestampFieldsMessage != null) { + wrapperWarnings.push(warningMissingTimestampFieldsMessage); } + skipExecution = foundNoIndices; } } catch (exc) { await ruleExecutionLogger.logStatusChange({ newStatus: RuleExecutionStatusEnum['partial failure'], message: `Check privileges failed to execute ${exc}`, }); - wroteWarningStatus = true; + wrapperWarnings.push(`Check privileges failed to execute ${exc}`); } const { tuples, remainingGap, - wroteWarningStatus: rangeTuplesWarningStatus, warningStatusMessage: rangeTuplesWarningMessage, } = await getRuleRangeTuples({ startedAt, @@ -326,19 +321,17 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper = ruleExecutionLogger, alerting, }); - if (rangeTuplesWarningStatus) { - wroteWarningStatus = rangeTuplesWarningStatus; - warningMessage = rangeTuplesWarningMessage; + if (rangeTuplesWarningMessage != null) { + wrapperWarnings.push(rangeTuplesWarningMessage); } if (remainingGap.asMilliseconds() > 0) { - hasError = true; - const gapDuration = `${remainingGap.humanize()} (${remainingGap.asMilliseconds()}ms)`; - + const gapErrorMessage = `${gapDuration} were not queried between this rule execution and the last execution, so signals may have been missed. Consider increasing your look behind time or adding more Kibana instances`; + wrapperErrors.push(gapErrorMessage); await ruleExecutionLogger.logStatusChange({ newStatus: RuleExecutionStatusEnum.failed, - message: `${gapDuration} were not queried between this rule execution and the last execution, so signals may have been missed. Consider increasing your look behind time or adding more Kibana instances`, + message: gapErrorMessage, metrics: { executionGap: remainingGap }, }); } @@ -492,21 +485,16 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper = alertsCreated: createdSignalsCount > 0, disabledActions, }); - if (result.warningMessages.length) { - result.warningMessages.push(disabledActionsWarning); - } else { - warningMessage = [ - ...(warningMessage ? [warningMessage] : []), - disabledActionsWarning, - ].join(', '); - wroteWarningStatus = true; - } + wrapperWarnings.push(disabledActionsWarning); } - if (result.warningMessages.length) { + if (result.warningMessages.length > 0 || wrapperWarnings.length > 0) { + // write warning messages first because if we have still have an error to write + // we want to write the error messages last, so that the errors are set + // as the current status of the rule. await ruleExecutionLogger.logStatusChange({ newStatus: RuleExecutionStatusEnum['partial failure'], - message: truncateList(result.warningMessages).join(', '), + message: truncateList(result.warningMessages.concat(wrapperWarnings)).join(', '), metrics: { searchDurations: result.searchAfterTimes, indexingDurations: result.bulkCreateTimes, @@ -514,8 +502,19 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper = }, }); } - - if (result.success) { + if (wrapperErrors.length > 0 || result.errors.length > 0) { + await ruleExecutionLogger.logStatusChange({ + newStatus: RuleExecutionStatusEnum.failed, + message: truncateList(result.errors.concat(wrapperErrors)).join(', '), + metrics: { + searchDurations: result.searchAfterTimes, + indexingDurations: result.bulkCreateTimes, + enrichmentDurations: result.enrichmentTimes, + executionGap: remainingGap, + }, + userError: result.userError, + }); + } else if (!(result.warningMessages.length > 0) && !(wrapperWarnings.length > 0)) { ruleExecutionLogger.debug('Security Rule execution completed'); ruleExecutionLogger.debug( `Finished indexing ${createdSignalsCount} alerts into ${ruleDataClient.indexNameWithNamespace( @@ -526,40 +525,14 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper = : '' }` ); - - if (!hasError && !wroteWarningStatus && !result.warning) { - await ruleExecutionLogger.logStatusChange({ - newStatus: RuleExecutionStatusEnum.succeeded, - message: 'Rule execution completed successfully', - metrics: { - searchDurations: result.searchAfterTimes, - indexingDurations: result.bulkCreateTimes, - enrichmentDurations: result.enrichmentTimes, - }, - }); - } else if (wroteWarningStatus && !hasError && !result.warning) { - await ruleExecutionLogger.logStatusChange({ - newStatus: RuleExecutionStatusEnum['partial failure'], - message: warningMessage, - metrics: { - searchDurations: result.searchAfterTimes, - indexingDurations: result.bulkCreateTimes, - enrichmentDurations: result.enrichmentTimes, - }, - }); - } - } else { await ruleExecutionLogger.logStatusChange({ - newStatus: RuleExecutionStatusEnum.failed, - message: `An error occurred during rule execution: message: "${truncateList( - result.errors - ).join()}"`, + newStatus: RuleExecutionStatusEnum.succeeded, + message: 'Rule execution completed successfully', metrics: { searchDurations: result.searchAfterTimes, indexingDurations: result.bulkCreateTimes, enrichmentDurations: result.enrichmentTimes, }, - userError: result.userError, }); } } catch (error) { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/create_query_alert_type.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/create_query_alert_type.test.ts index 1392c84aa044f..84f5817413a4a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/create_query_alert_type.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/create_query_alert_type.test.ts @@ -18,10 +18,19 @@ import { sampleDocNoSortId } from '../__mocks__/es_results'; import { getQueryRuleParams } from '../../rule_schema/mocks'; import { licensingMock } from '@kbn/licensing-plugin/server/mocks'; import { QUERY_RULE_TYPE_ID } from '@kbn/securitysolution-rules'; +import { hasTimestampFields } from '../utils/utils'; +import { RuleExecutionStatusEnum } from '../../../../../common/api/detection_engine'; jest.mock('../utils/utils', () => ({ ...jest.requireActual('../utils/utils'), getExceptions: () => [], + hasTimestampFields: jest.fn(async () => { + return { + foundNoIndices: false, + warningMessage: undefined, + }; + }), + hasReadIndexPrivileges: jest.fn(async () => undefined), })); jest.mock('../utils/get_list_client', () => ({ @@ -35,6 +44,8 @@ describe('Custom Query Alerts', () => { const mocks = createRuleTypeMocks(); const licensing = licensingMock.createSetup(); const publicBaseUrl = 'http://somekibanabaseurl.com'; + const mockedStatusLogger = ruleExecutionLogMock.forExecutors.create(); + const ruleStatusLogger = () => Promise.resolve(mockedStatusLogger); const { dependencies, executor, services } = mocks; const { actions, alerting, lists, logger, ruleDataClient } = dependencies; @@ -44,7 +55,7 @@ describe('Custom Query Alerts', () => { logger, config: createMockConfig(), ruleDataClient, - ruleExecutionLoggerFactory: () => Promise.resolve(ruleExecutionLogMock.forExecutors.create()), + ruleExecutionLoggerFactory: ruleStatusLogger, version: '8.3', publicBaseUrl, alerting, @@ -148,4 +159,62 @@ describe('Custom Query Alerts', () => { expect((await ruleDataClient.getWriter()).bulk).toHaveBeenCalled(); expect(eventsTelemetry.sendAsync).toHaveBeenCalled(); }); + + it('sends an alert when events are found and logs a warning when hasTimestampFields throws an error', async () => { + (hasTimestampFields as jest.Mock).mockImplementationOnce(async () => { + throw Error('hastTimestampFields test error'); + }); + const queryAlertType = securityRuleTypeWrapper( + createQueryAlertType({ + eventsTelemetry, + licensing, + scheduleNotificationResponseActionsService: () => null, + experimentalFeatures: allowedExperimentalValues, + logger, + version: '1.0.0', + id: QUERY_RULE_TYPE_ID, + name: 'Custom Query Rule', + }) + ); + + alerting.registerType(queryAlertType); + + services.scopedClusterClient.asCurrentUser.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ + hits: { + hits: [sampleDocNoSortId()], + sequences: [], + events: [], + total: { + relation: 'eq', + value: 1, + }, + }, + took: 0, + timed_out: false, + _shards: { + failed: 0, + skipped: 0, + successful: 1, + total: 1, + }, + }) + ); + + const params = getQueryRuleParams(); + + await executor({ params }); + + expect((await ruleDataClient.getWriter()).bulk).toHaveBeenCalled(); + expect(eventsTelemetry.sendAsync).toHaveBeenCalled(); + // ensures that the last status written is a warning status + // and that status contains the error message + expect(mockedStatusLogger.logStatusChange).lastCalledWith( + expect.objectContaining({ + newStatus: RuleExecutionStatusEnum['partial failure'], + message: + "Check privileges failed to execute Error: hastTimestampFields test error, The rule's max alerts per run setting (10000) is greater than the Kibana alerting limit (1000). The rule will only write a maximum of 1000 alerts per rule run.", + }) + ); + }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/utils.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/utils.test.ts index a7895ba229cc8..5397d473af3c8 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/utils.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/utils.test.ts @@ -454,76 +454,69 @@ describe('utils', () => { }); test('should return a single tuple if no gap', async () => { - const { tuples, remainingGap, wroteWarningStatus, warningStatusMessage } = - await getRuleRangeTuples({ - previousStartedAt: moment().subtract(30, 's').toDate(), - startedAt: moment().subtract(30, 's').toDate(), - interval: '30s', - from: 'now-30s', - to: 'now', - maxSignals: 20, - ruleExecutionLogger, - alerting, - }); + const { tuples, remainingGap, warningStatusMessage } = await getRuleRangeTuples({ + previousStartedAt: moment().subtract(30, 's').toDate(), + startedAt: moment().subtract(30, 's').toDate(), + interval: '30s', + from: 'now-30s', + to: 'now', + maxSignals: 20, + ruleExecutionLogger, + alerting, + }); const someTuple = tuples[0]; expect(moment(someTuple.to).diff(moment(someTuple.from), 's')).toEqual(30); expect(tuples.length).toEqual(1); expect(remainingGap.asMilliseconds()).toEqual(0); - expect(wroteWarningStatus).toEqual(false); expect(warningStatusMessage).toEqual(undefined); }); test('should return a single tuple if malformed interval prevents gap calculation', async () => { - const { tuples, remainingGap, wroteWarningStatus, warningStatusMessage } = - await getRuleRangeTuples({ - previousStartedAt: moment().subtract(30, 's').toDate(), - startedAt: moment().subtract(30, 's').toDate(), - interval: 'invalid', - from: 'now-30s', - to: 'now', - maxSignals: 20, - ruleExecutionLogger, - alerting, - }); + const { tuples, remainingGap, warningStatusMessage } = await getRuleRangeTuples({ + previousStartedAt: moment().subtract(30, 's').toDate(), + startedAt: moment().subtract(30, 's').toDate(), + interval: 'invalid', + from: 'now-30s', + to: 'now', + maxSignals: 20, + ruleExecutionLogger, + alerting, + }); const someTuple = tuples[0]; expect(moment(someTuple.to).diff(moment(someTuple.from), 's')).toEqual(30); expect(tuples.length).toEqual(1); expect(remainingGap.asMilliseconds()).toEqual(0); - expect(wroteWarningStatus).toEqual(false); expect(warningStatusMessage).toEqual(undefined); }); test('should return two tuples if gap and previouslyStartedAt', async () => { - const { tuples, remainingGap, wroteWarningStatus, warningStatusMessage } = - await getRuleRangeTuples({ - previousStartedAt: moment().subtract(65, 's').toDate(), - startedAt: moment().toDate(), - interval: '50s', - from: 'now-55s', - to: 'now', - maxSignals: 20, - ruleExecutionLogger, - alerting, - }); + const { tuples, remainingGap, warningStatusMessage } = await getRuleRangeTuples({ + previousStartedAt: moment().subtract(65, 's').toDate(), + startedAt: moment().toDate(), + interval: '50s', + from: 'now-55s', + to: 'now', + maxSignals: 20, + ruleExecutionLogger, + alerting, + }); const someTuple = tuples[1]; expect(moment(someTuple.to).diff(moment(someTuple.from), 's')).toEqual(55); expect(remainingGap.asMilliseconds()).toEqual(0); - expect(wroteWarningStatus).toEqual(false); expect(warningStatusMessage).toEqual(undefined); }); test('should return five tuples when give long gap', async () => { - const { tuples, remainingGap, wroteWarningStatus, warningStatusMessage } = - await getRuleRangeTuples({ - previousStartedAt: moment().subtract(65, 's').toDate(), // 64 is 5 times the interval + lookback, which will trigger max lookback - startedAt: moment().toDate(), - interval: '10s', - from: 'now-13s', - to: 'now', - maxSignals: 20, - ruleExecutionLogger, - alerting, - }); + const { tuples, remainingGap, warningStatusMessage } = await getRuleRangeTuples({ + previousStartedAt: moment().subtract(65, 's').toDate(), // 64 is 5 times the interval + lookback, which will trigger max lookback + startedAt: moment().toDate(), + interval: '10s', + from: 'now-13s', + to: 'now', + maxSignals: 20, + ruleExecutionLogger, + alerting, + }); expect(tuples.length).toEqual(5); tuples.forEach((item, index) => { if (index === 0) { @@ -534,33 +527,30 @@ describe('utils', () => { expect(item.from.diff(tuples[index - 1].from, 's')).toEqual(10); }); expect(remainingGap.asMilliseconds()).toEqual(12000); - expect(wroteWarningStatus).toEqual(false); expect(warningStatusMessage).toEqual(undefined); }); test('should return a single tuple when give a negative gap (rule ran sooner than expected)', async () => { - const { tuples, remainingGap, wroteWarningStatus, warningStatusMessage } = - await getRuleRangeTuples({ - previousStartedAt: moment().subtract(-15, 's').toDate(), - startedAt: moment().subtract(-15, 's').toDate(), - interval: '10s', - from: 'now-13s', - to: 'now', - maxSignals: 20, - ruleExecutionLogger, - alerting, - }); + const { tuples, remainingGap, warningStatusMessage } = await getRuleRangeTuples({ + previousStartedAt: moment().subtract(-15, 's').toDate(), + startedAt: moment().subtract(-15, 's').toDate(), + interval: '10s', + from: 'now-13s', + to: 'now', + maxSignals: 20, + ruleExecutionLogger, + alerting, + }); expect(tuples.length).toEqual(1); const someTuple = tuples[0]; expect(moment(someTuple.to).diff(moment(someTuple.from), 's')).toEqual(13); expect(remainingGap.asMilliseconds()).toEqual(0); - expect(wroteWarningStatus).toEqual(false); expect(warningStatusMessage).toEqual(undefined); }); test('should use alerting framework max alerts value if maxSignals is greater than limit', async () => { alerting.getConfig = jest.fn().mockReturnValue({ run: { alerts: { max: 10 } } }); - const { tuples, wroteWarningStatus, warningStatusMessage } = await getRuleRangeTuples({ + const { tuples, warningStatusMessage } = await getRuleRangeTuples({ previousStartedAt: moment().subtract(30, 's').toDate(), startedAt: moment().subtract(30, 's').toDate(), interval: '30s', @@ -573,14 +563,13 @@ describe('utils', () => { const someTuple = tuples[0]; expect(someTuple.maxSignals).toEqual(10); expect(tuples.length).toEqual(1); - expect(wroteWarningStatus).toEqual(true); expect(warningStatusMessage).toEqual( "The rule's max alerts per run setting (20) is greater than the Kibana alerting limit (10). The rule will only write a maximum of 10 alerts per rule run." ); }); test('should use maxSignals value if maxSignals is less than alerting framework limit', async () => { - const { tuples, wroteWarningStatus, warningStatusMessage } = await getRuleRangeTuples({ + const { tuples, warningStatusMessage } = await getRuleRangeTuples({ previousStartedAt: moment().subtract(30, 's').toDate(), startedAt: moment().subtract(30, 's').toDate(), interval: '30s', @@ -593,7 +582,6 @@ describe('utils', () => { const someTuple = tuples[0]; expect(someTuple.maxSignals).toEqual(20); expect(tuples.length).toEqual(1); - expect(wroteWarningStatus).toEqual(false); expect(warningStatusMessage).toEqual(undefined); }); }); @@ -712,7 +700,7 @@ describe('utils', () => { }, }; - const { wroteWarningStatus, foundNoIndices } = await hasTimestampFields({ + const { foundNoIndices } = await hasTimestampFields({ timestampField, timestampFieldCapsResponse: timestampFieldCapsResponse as TransportResult< // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -722,7 +710,6 @@ describe('utils', () => { ruleExecutionLogger, }); - expect(wroteWarningStatus).toBeTruthy(); expect(foundNoIndices).toBeFalsy(); expect(ruleExecutionLogger.logStatusChange).toHaveBeenCalledWith({ newStatus: RuleExecutionStatusEnum['partial failure'], @@ -756,7 +743,7 @@ describe('utils', () => { }, }; - const { wroteWarningStatus, foundNoIndices } = await hasTimestampFields({ + const { foundNoIndices } = await hasTimestampFields({ timestampField, timestampFieldCapsResponse: timestampFieldCapsResponse as TransportResult< // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -766,7 +753,6 @@ describe('utils', () => { ruleExecutionLogger, }); - expect(wroteWarningStatus).toBeTruthy(); expect(foundNoIndices).toBeFalsy(); expect(ruleExecutionLogger.logStatusChange).toHaveBeenCalledWith({ newStatus: RuleExecutionStatusEnum['partial failure'], @@ -789,7 +775,7 @@ describe('utils', () => { ruleName: 'Endpoint Security', }); - const { wroteWarningStatus, foundNoIndices } = await hasTimestampFields({ + const { foundNoIndices } = await hasTimestampFields({ timestampField, timestampFieldCapsResponse: timestampFieldCapsResponse as TransportResult< // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -799,7 +785,6 @@ describe('utils', () => { ruleExecutionLogger, }); - expect(wroteWarningStatus).toBeTruthy(); expect(foundNoIndices).toBeTruthy(); expect(ruleExecutionLogger.logStatusChange).toHaveBeenCalledWith({ newStatus: RuleExecutionStatusEnum['partial failure'], @@ -823,7 +808,7 @@ describe('utils', () => { ruleName: 'NOT Endpoint Security', }); - const { wroteWarningStatus, foundNoIndices } = await hasTimestampFields({ + const { foundNoIndices } = await hasTimestampFields({ timestampField, timestampFieldCapsResponse: timestampFieldCapsResponse as TransportResult< // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -833,7 +818,6 @@ describe('utils', () => { ruleExecutionLogger, }); - expect(wroteWarningStatus).toBeTruthy(); expect(foundNoIndices).toBeTruthy(); expect(ruleExecutionLogger.logStatusChange).toHaveBeenCalledWith({ newStatus: RuleExecutionStatusEnum['partial failure'], diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/utils.ts index e67659b525342..927a5170d293c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/utils.ts @@ -74,7 +74,7 @@ export const hasReadIndexPrivileges = async (args: { privileges: Privilege; ruleExecutionLogger: IRuleExecutionLogForExecutors; uiSettingsClient: IUiSettingsClient; -}): Promise<{ wroteWarningMessage: boolean; warningStatusMessage: string | undefined }> => { +}): Promise => { const { privileges, ruleExecutionLogger, uiSettingsClient } = args; const isCcsPermissionWarningEnabled = await uiSettingsClient.get(ENABLE_CCS_READ_WARNING_SETTING); @@ -99,10 +99,9 @@ export const hasReadIndexPrivileges = async (args: { newStatus: RuleExecutionStatusEnum['partial failure'], message: warningStatusMessage, }); - return { wroteWarningMessage: true, warningStatusMessage }; } - return { wroteWarningMessage: false, warningStatusMessage }; + return warningStatusMessage; }; export const hasTimestampFields = async (args: { @@ -114,7 +113,6 @@ export const hasTimestampFields = async (args: { inputIndices: string[]; ruleExecutionLogger: IRuleExecutionLogForExecutors; }): Promise<{ - wroteWarningStatus: boolean; foundNoIndices: boolean; warningMessage: string | undefined; }> => { @@ -136,7 +134,6 @@ export const hasTimestampFields = async (args: { }); return { - wroteWarningStatus: true, foundNoIndices: true, warningMessage: errorString.trimEnd(), }; @@ -163,10 +160,10 @@ export const hasTimestampFields = async (args: { message: errorString, }); - return { wroteWarningStatus: true, foundNoIndices: false, warningMessage: errorString }; + return { foundNoIndices: false, warningMessage: errorString }; } - return { wroteWarningStatus: false, foundNoIndices: false, warningMessage: undefined }; + return { foundNoIndices: false, warningMessage: undefined }; }; export const checkPrivileges = async ( @@ -433,7 +430,6 @@ export const getRuleRangeTuples = async ({ }) => { const originalFrom = dateMath.parse(from, { forceNow: startedAt }); const originalTo = dateMath.parse(to, { forceNow: startedAt }); - let wroteWarningStatus = false; let warningStatusMessage; if (originalFrom == null || originalTo == null) { throw new Error('Failed to parse date math of rule.from or rule.to'); @@ -448,7 +444,6 @@ export const getRuleRangeTuples = async ({ newStatus: RuleExecutionStatusEnum['partial failure'], message: warningStatusMessage, }); - wroteWarningStatus = true; } const tuples = [ @@ -466,7 +461,7 @@ export const getRuleRangeTuples = async ({ interval )}"` ); - return { tuples, remainingGap: moment.duration(0), wroteWarningStatus, warningStatusMessage }; + return { tuples, remainingGap: moment.duration(0), warningStatusMessage }; } const gap = getGapBetweenRuns({ @@ -498,7 +493,6 @@ export const getRuleRangeTuples = async ({ return { tuples: tuples.reverse(), remainingGap: moment.duration(remainingGapMilliseconds), - wroteWarningStatus, warningStatusMessage, }; }; diff --git a/x-pack/plugins/security_solution/server/lib/product_features_service/mocks.ts b/x-pack/plugins/security_solution/server/lib/product_features_service/mocks.ts index 2298c55fca6aa..dfc86518e124f 100644 --- a/x-pack/plugins/security_solution/server/lib/product_features_service/mocks.ts +++ b/x-pack/plugins/security_solution/server/lib/product_features_service/mocks.ts @@ -6,7 +6,7 @@ */ import type { Logger } from '@kbn/core/server'; -import type { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import type { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { featuresPluginMock } from '@kbn/features-plugin/server/mocks'; diff --git a/x-pack/plugins/security_solution/server/lib/product_features_service/product_features.test.ts b/x-pack/plugins/security_solution/server/lib/product_features_service/product_features.test.ts index d86e38efce52d..958d952e7ec23 100644 --- a/x-pack/plugins/security_solution/server/lib/product_features_service/product_features.test.ts +++ b/x-pack/plugins/security_solution/server/lib/product_features_service/product_features.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { PluginSetupContract } from '@kbn/features-plugin/server'; +import type { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { ProductFeatures } from './product_features'; import type { @@ -150,7 +150,7 @@ describe('ProductFeatures', () => { const featuresSetup = { registerKibanaFeature: jest.fn(), getKibanaFeatures: jest.fn(), - } as unknown as PluginSetupContract; + } as unknown as FeaturesPluginSetup; const productFeatures = new ProductFeatures( loggingSystemMock.create().get('mock'), @@ -171,7 +171,7 @@ describe('ProductFeatures', () => { const featuresSetup = { registerKibanaFeature: jest.fn(), getKibanaFeatures: jest.fn(), - } as unknown as PluginSetupContract; + } as unknown as FeaturesPluginSetup; const productFeatures = new ProductFeatures( loggingSystemMock.create().get('mock'), @@ -195,7 +195,7 @@ describe('ProductFeatures', () => { const featuresSetup = { registerKibanaFeature: jest.fn(), getKibanaFeatures: jest.fn(), - } as unknown as PluginSetupContract; + } as unknown as FeaturesPluginSetup; const productFeatures = new ProductFeatures( loggingSystemMock.create().get('mock'), @@ -222,7 +222,7 @@ describe('ProductFeatures', () => { const featuresSetup = { registerKibanaFeature: jest.fn(), getKibanaFeatures: jest.fn(), - } as unknown as PluginSetupContract; + } as unknown as FeaturesPluginSetup; const productFeatures = new ProductFeatures( loggingSystemMock.create().get('mock'), @@ -250,7 +250,7 @@ describe('ProductFeatures', () => { it('should register base privilege actions', () => { const featuresSetup = { registerKibanaFeature: jest.fn(), - } as unknown as PluginSetupContract; + } as unknown as FeaturesPluginSetup; const productFeatures = new ProductFeatures( loggingSystemMock.create().get('mock'), @@ -276,7 +276,7 @@ describe('ProductFeatures', () => { it('should register config privilege actions', () => { const featuresSetup = { registerKibanaFeature: jest.fn(), - } as unknown as PluginSetupContract; + } as unknown as FeaturesPluginSetup; const productFeatures = new ProductFeatures( loggingSystemMock.create().get('mock'), @@ -304,7 +304,7 @@ describe('ProductFeatures', () => { it('should register config sub-feature privilege actions', () => { const featuresSetup = { registerKibanaFeature: jest.fn(), - } as unknown as PluginSetupContract; + } as unknown as FeaturesPluginSetup; const productFeatures = new ProductFeatures( loggingSystemMock.create().get('mock'), @@ -335,7 +335,7 @@ describe('ProductFeatures', () => { it('should register default and config sub-feature privilege actions', () => { const featuresSetup = { registerKibanaFeature: jest.fn(), - } as unknown as PluginSetupContract; + } as unknown as FeaturesPluginSetup; const productFeatures = new ProductFeatures( loggingSystemMock.create().get('mock'), diff --git a/x-pack/plugins/security_solution/server/lib/product_features_service/product_features.ts b/x-pack/plugins/security_solution/server/lib/product_features_service/product_features.ts index cee8559d8b693..5433c7572e9b5 100644 --- a/x-pack/plugins/security_solution/server/lib/product_features_service/product_features.ts +++ b/x-pack/plugins/security_solution/server/lib/product_features_service/product_features.ts @@ -9,7 +9,7 @@ import type { Logger } from '@kbn/core/server'; import type { FeatureKibanaPrivileges, KibanaFeatureConfig, - PluginSetupContract as FeaturesPluginSetup, + FeaturesPluginSetup, } from '@kbn/features-plugin/server'; import type { ProductFeaturesConfig, diff --git a/x-pack/plugins/security_solution/server/lib/product_features_service/product_features_service.ts b/x-pack/plugins/security_solution/server/lib/product_features_service/product_features_service.ts index 30cb343e84bf2..8714c2e4ab6ab 100644 --- a/x-pack/plugins/security_solution/server/lib/product_features_service/product_features_service.ts +++ b/x-pack/plugins/security_solution/server/lib/product_features_service/product_features_service.ts @@ -13,7 +13,7 @@ import type { HttpServiceSetup, Logger } from '@kbn/core/server'; import { hiddenTypes as filesSavedObjectTypes } from '@kbn/files-plugin/server/saved_objects'; -import type { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import type { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import type { ProductFeatureKeyType } from '@kbn/security-solution-features'; import { getAssistantFeature, diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/receiver.ts b/x-pack/plugins/security_solution/server/lib/telemetry/receiver.ts index bddee1c6a1f28..ebff5655d99e0 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/receiver.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/receiver.ts @@ -313,6 +313,7 @@ export class TelemetryReceiver implements ITelemetryReceiver { ?.listAgents({ perPage: this.maxRecords, showInactive: true, + kuery: 'status:*', // include unenrolled agents sortField: 'enrolled_at', sortOrder: 'desc', }) diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index be4d5ae275d83..e1a5c1247c3cf 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -19,18 +19,13 @@ import type { ILicense } from '@kbn/licensing-plugin/server'; import type { NewPackagePolicy, UpdatePackagePolicy } from '@kbn/fleet-plugin/common'; import { FLEET_ENDPOINT_PACKAGE } from '@kbn/fleet-plugin/common'; -import { i18n } from '@kbn/i18n'; import { CompleteExternalResponseActionsTask } from './endpoint/lib/response_actions'; import { registerAgentRoutes } from './endpoint/routes/agent'; import { endpointPackagePoliciesStatsSearchStrategyProvider } from './search_strategy/endpoint_package_policies_stats'; import { turnOffPolicyProtectionsIfNotSupported } from './endpoint/migrations/turn_off_policy_protections'; import { endpointSearchStrategyProvider } from './search_strategy/endpoint'; import { getScheduleNotificationResponseActionsService } from './lib/detection_engine/rule_response_actions/schedule_notification_response_actions'; -import { - siemGuideId, - getSiemGuideConfig, - defaultGuideTranslations, -} from '../common/guided_onboarding/siem_guide_config'; +import { siemGuideId, getSiemGuideConfig } from '../common/guided_onboarding/siem_guide_config'; import { createEqlAlertType, createEsqlAlertType, @@ -461,28 +456,7 @@ export class Plugin implements ISecuritySolutionPlugin { /** * Register a config for the security guide */ - if (depsStart.cloudExperiments && i18n.getLocale() === 'en') { - try { - const variation = await depsStart.cloudExperiments.getVariation( - 'security-solutions.guided-onboarding-content', - defaultGuideTranslations - ); - plugins.guidedOnboarding?.registerGuideConfig( - siemGuideId, - getSiemGuideConfig(variation) - ); - } catch { - plugins.guidedOnboarding?.registerGuideConfig( - siemGuideId, - getSiemGuideConfig(defaultGuideTranslations) - ); - } - } else { - plugins.guidedOnboarding?.registerGuideConfig( - siemGuideId, - getSiemGuideConfig(defaultGuideTranslations) - ); - } + plugins.guidedOnboarding?.registerGuideConfig(siemGuideId, getSiemGuideConfig()); }) .catch(() => {}); // it shouldn't reject, but just in case diff --git a/x-pack/plugins/security_solution/server/plugin_contract.ts b/x-pack/plugins/security_solution/server/plugin_contract.ts index 3736e30ba3480..c7ec67c1b07fc 100644 --- a/x-pack/plugins/security_solution/server/plugin_contract.ts +++ b/x-pack/plugins/security_solution/server/plugin_contract.ts @@ -23,7 +23,7 @@ import type { import type { CasesServerStart, CasesServerSetup } from '@kbn/cases-plugin/server'; import type { EncryptedSavedObjectsPluginSetup } from '@kbn/encrypted-saved-objects-plugin/server'; import type { IEventLogClientService, IEventLogService } from '@kbn/event-log-plugin/server'; -import type { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import type { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import type { FleetStartContract as FleetPluginStart } from '@kbn/fleet-plugin/server'; import type { LicensingPluginStart, LicensingPluginSetup } from '@kbn/licensing-plugin/server'; import type { ListPluginSetup } from '@kbn/lists-plugin/server'; @@ -41,7 +41,6 @@ import type { import type { TelemetryPluginStart, TelemetryPluginSetup } from '@kbn/telemetry-plugin/server'; import type { OsqueryPluginSetup } from '@kbn/osquery-plugin/server'; import type { CloudSetup } from '@kbn/cloud-plugin/server'; -import type { CloudExperimentsPluginStart } from '@kbn/cloud-experiments-plugin/common'; import type { SharePluginStart } from '@kbn/share-plugin/server'; import type { GuidedOnboardingPluginSetup } from '@kbn/guided-onboarding-plugin/server'; import type { PluginSetup as UnifiedSearchServerPluginSetup } from '@kbn/unified-search-plugin/server'; @@ -76,7 +75,6 @@ export interface SecuritySolutionPluginStartDependencies { alerting: AlertingPluginStart; cases?: CasesServerStart; cloud: CloudSetup; - cloudExperiments?: CloudExperimentsPluginStart; data: DataPluginStart; dataViews: DataViewsPluginStart; elasticAssistant: ElasticAssistantPluginStart; diff --git a/x-pack/plugins/security_solution/tsconfig.json b/x-pack/plugins/security_solution/tsconfig.json index 001a6e1b72d4b..ba89ca2864d74 100644 --- a/x-pack/plugins/security_solution/tsconfig.json +++ b/x-pack/plugins/security_solution/tsconfig.json @@ -207,5 +207,6 @@ "@kbn/core-i18n-browser", "@kbn/core-theme-browser", "@kbn/integration-assistant-plugin", + "@kbn/avc-banner", ] } diff --git a/x-pack/plugins/security_solution_ess/kibana.jsonc b/x-pack/plugins/security_solution_ess/kibana.jsonc index 03c4d6a980925..b77bafa226adb 100644 --- a/x-pack/plugins/security_solution_ess/kibana.jsonc +++ b/x-pack/plugins/security_solution_ess/kibana.jsonc @@ -14,9 +14,7 @@ "navigation", "licensing", ], - "optionalPlugins": [ - "cloudExperiments", - ], + "optionalPlugins": [], "requiredBundles": [ "kibanaReact"] } } diff --git a/x-pack/plugins/security_solution_ess/public/common/hooks/use_variation.test.ts b/x-pack/plugins/security_solution_ess/public/common/hooks/use_variation.test.ts deleted file mode 100644 index 206969280a7c7..0000000000000 --- a/x-pack/plugins/security_solution_ess/public/common/hooks/use_variation.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { renderHook } from '@testing-library/react-hooks'; -import { cloudExperimentsMock } from '@kbn/cloud-experiments-plugin/common/mocks'; -import { useVariation } from './use_variation'; - -describe('useVariation', () => { - test('it should call the setter if cloudExperiments is enabled', async () => { - const cloudExperiments = cloudExperimentsMock.createStartMock(); - cloudExperiments.getVariation.mockResolvedValue('resolved value'); - const setter = jest.fn(); - const { result } = renderHook(() => - useVariation( - cloudExperiments, - 'security-solutions.add-integrations-url', - 'my default value', - setter - ) - ); - await new Promise((resolve) => process.nextTick(resolve)); - expect(result.error).toBe(undefined); - expect(setter).toHaveBeenCalledTimes(1); - expect(setter).toHaveBeenCalledWith('resolved value'); - }); - - test('it should not call the setter if cloudExperiments is not enabled', async () => { - const setter = jest.fn(); - const { result } = renderHook(() => - useVariation(undefined, 'security-solutions.add-integrations-url', 'my default value', setter) - ); - await new Promise((resolve) => process.nextTick(resolve)); - expect(result.error).toBe(undefined); - expect(setter).not.toHaveBeenCalled(); - }); -}); diff --git a/x-pack/plugins/security_solution_ess/public/common/hooks/use_variation.ts b/x-pack/plugins/security_solution_ess/public/common/hooks/use_variation.ts deleted file mode 100644 index 251470edc915d..0000000000000 --- a/x-pack/plugins/security_solution_ess/public/common/hooks/use_variation.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { useEffect } from 'react'; -import type { - CloudExperimentsFeatureFlagNames, - CloudExperimentsPluginStart, -} from '@kbn/cloud-experiments-plugin/common'; -/** - * Retrieves the variation of the feature flag if the cloudExperiments plugin is enabled. - * @param cloudExperiments {@link CloudExperimentsPluginStart} - * @param featureFlagName The name of the feature flag {@link CloudExperimentsFeatureFlagNames} - * @param defaultValue The default value in case it cannot retrieve the feature flag - * @param setter The setter from {@link useState} to update the value. - */ -export const useVariation = ( - cloudExperiments: CloudExperimentsPluginStart | undefined, - featureFlagName: CloudExperimentsFeatureFlagNames, - defaultValue: Data, - setter: (value: Data) => void -) => { - useEffect(() => { - (async function loadVariation() { - const variationUrl = await cloudExperiments?.getVariation(featureFlagName, defaultValue); - if (variationUrl) { - setter(variationUrl); - } - })(); - }, [cloudExperiments, featureFlagName, defaultValue, setter]); -}; diff --git a/x-pack/plugins/security_solution_ess/public/types.ts b/x-pack/plugins/security_solution_ess/public/types.ts index d9fcc7215a981..6f4fd44a7221f 100644 --- a/x-pack/plugins/security_solution_ess/public/types.ts +++ b/x-pack/plugins/security_solution_ess/public/types.ts @@ -9,7 +9,6 @@ import type { PluginSetup as SecuritySolutionPluginSetup, PluginStart as SecuritySolutionPluginStart, } from '@kbn/security-solution-plugin/public'; -import type { CloudExperimentsPluginStart } from '@kbn/cloud-experiments-plugin/common'; import type { LicensingPluginStart } from '@kbn/licensing-plugin/public'; import type { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public'; import type { ManagementStart } from '@kbn/management-plugin/public'; @@ -26,7 +25,6 @@ export interface SecuritySolutionEssPluginSetupDeps { export interface SecuritySolutionEssPluginStartDeps { securitySolution: SecuritySolutionPluginStart; - cloudExperiments?: CloudExperimentsPluginStart; licensing: LicensingPluginStart; navigation: NavigationPublicPluginStart; management: ManagementStart; diff --git a/x-pack/plugins/security_solution_ess/tsconfig.json b/x-pack/plugins/security_solution_ess/tsconfig.json index 5765bc18f816c..f38811b701391 100644 --- a/x-pack/plugins/security_solution_ess/tsconfig.json +++ b/x-pack/plugins/security_solution_ess/tsconfig.json @@ -16,7 +16,6 @@ "@kbn/core", "@kbn/config-schema", "@kbn/security-solution-plugin", - "@kbn/cloud-experiments-plugin", "@kbn/kibana-react-plugin", "@kbn/security-solution-features", "@kbn/cases-plugin", diff --git a/x-pack/plugins/security_solution_serverless/server/types.ts b/x-pack/plugins/security_solution_serverless/server/types.ts index 8f8d4b36041a1..4f3a7bf3c3db0 100644 --- a/x-pack/plugins/security_solution_serverless/server/types.ts +++ b/x-pack/plugins/security_solution_serverless/server/types.ts @@ -6,7 +6,7 @@ */ import type { CoreSetup, ElasticsearchClient, Logger, LoggerFactory } from '@kbn/core/server'; import type { SecurityPluginSetup, SecurityPluginStart } from '@kbn/security-plugin/server'; -import type { PluginSetupContract, PluginStartContract } from '@kbn/features-plugin/server'; +import type { FeaturesPluginSetup, FeaturesPluginStart } from '@kbn/features-plugin/server'; import type { PluginSetup as SecuritySolutionPluginSetup, PluginStart as SecuritySolutionPluginStart, @@ -36,7 +36,7 @@ export interface SecuritySolutionServerlessPluginSetupDeps { securitySolution: SecuritySolutionPluginSetup; securitySolutionEss: SecuritySolutionEssPluginSetup; serverless: ServerlessPluginSetup; - features: PluginSetupContract; + features: FeaturesPluginSetup; taskManager: TaskManagerSetupContract; cloud: CloudSetup; actions: ActionsPluginSetupContract; @@ -46,7 +46,7 @@ export interface SecuritySolutionServerlessPluginSetupDeps { export interface SecuritySolutionServerlessPluginStartDeps { security: SecurityPluginStart; securitySolution: SecuritySolutionPluginStart; - features: PluginStartContract; + features: FeaturesPluginStart; taskManager: TaskManagerStartContract; fleet: FleetStartContract; } diff --git a/x-pack/plugins/serverless_search/public/application/components/connectors/connector_config/connection_details_panel.tsx b/x-pack/plugins/serverless_search/public/application/components/connectors/connector_config/connection_details_panel.tsx index 20a48b3e3076d..3e2b04987e465 100644 --- a/x-pack/plugins/serverless_search/public/application/components/connectors/connector_config/connection_details_panel.tsx +++ b/x-pack/plugins/serverless_search/public/application/components/connectors/connector_config/connection_details_panel.tsx @@ -60,7 +60,7 @@ export const ConnectionDetails: React.FC = ({ service_type
    - + {Boolean(serviceType) && {serviceType}}
    diff --git a/x-pack/plugins/serverless_search/public/application/components/connectors/edit_connector.tsx b/x-pack/plugins/serverless_search/public/application/components/connectors/edit_connector.tsx index fcd67f30c4b59..78d4da85ab909 100644 --- a/x-pack/plugins/serverless_search/public/application/components/connectors/edit_connector.tsx +++ b/x-pack/plugins/serverless_search/public/application/components/connectors/edit_connector.tsx @@ -126,6 +126,7 @@ export const EditConnector: React.FC = () => { > = ({ onClick={() => setSelectedLanguage(language)} color={language.id === selectedLanguage ? 'primary' : 'plain'} data-test-subj={`${language.id}-client-panel`} + aria-label={i18n.translate( + 'xpack.serverlessSearch.languageGrid.selectButton.ariaLabel', + { + defaultMessage: 'Select "{client}" client', + values: { + client: language.id, + }, + } + )} > diff --git a/x-pack/plugins/snapshot_restore/server/types.ts b/x-pack/plugins/snapshot_restore/server/types.ts index 37220ef9fe59b..b5221235c4407 100644 --- a/x-pack/plugins/snapshot_restore/server/types.ts +++ b/x-pack/plugins/snapshot_restore/server/types.ts @@ -9,7 +9,7 @@ import type { IRouter, CustomRequestHandlerContext, IScopedClusterClient } from import { LicensingPluginSetup } from '@kbn/licensing-plugin/server'; import { SecurityPluginSetup } from '@kbn/security-plugin/server'; import { CloudSetup } from '@kbn/cloud-plugin/server'; -import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { License } from './services'; import { wrapEsError } from './lib'; import { handleEsError } from './shared_imports'; diff --git a/x-pack/plugins/spaces/server/plugin.ts b/x-pack/plugins/spaces/server/plugin.ts index 6ca6e27291f7d..89900deb03b83 100644 --- a/x-pack/plugins/spaces/server/plugin.ts +++ b/x-pack/plugins/spaces/server/plugin.ts @@ -16,10 +16,7 @@ import type { Plugin, PluginInitializerContext, } from '@kbn/core/server'; -import type { - PluginSetupContract as FeaturesPluginSetup, - PluginStartContract as FeaturesPluginStart, -} from '@kbn/features-plugin/server'; +import type { FeaturesPluginSetup, FeaturesPluginStart } from '@kbn/features-plugin/server'; import type { HomeServerPluginSetup } from '@kbn/home-plugin/server'; import type { LicensingPluginSetup } from '@kbn/licensing-plugin/server'; import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server'; diff --git a/x-pack/plugins/spaces/server/routes/views/index.ts b/x-pack/plugins/spaces/server/routes/views/index.ts index 495e0132059be..dfeead287e995 100644 --- a/x-pack/plugins/spaces/server/routes/views/index.ts +++ b/x-pack/plugins/spaces/server/routes/views/index.ts @@ -36,7 +36,7 @@ export function initSpacesViewsRoutes(deps: ViewRouteDeps) { async (context, request, response) => { try { const { uiSettings } = await context.core; - const defaultRoute = await uiSettings.client.get('defaultRoute'); + const defaultRoute = await uiSettings.client.get('defaultRoute', { request }); const basePath = deps.basePath.get(request); const nextCandidateRoute = parseNextURL(request.url.href); diff --git a/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/esql_query_expression.tsx b/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/esql_query_expression.tsx index e9ceabf4639b2..c836da9ce0b93 100644 --- a/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/esql_query_expression.tsx +++ b/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/esql_query_expression.tsx @@ -6,7 +6,6 @@ */ import React, { useState, Fragment, useEffect, useCallback } from 'react'; -import { get } from 'lodash'; import { FormattedMessage } from '@kbn/i18n-react'; import { EuiFieldNumber, @@ -19,7 +18,7 @@ import { import { getFields, RuleTypeParamsExpressionProps } from '@kbn/triggers-actions-ui-plugin/public'; import { TextBasedLangEditor } from '@kbn/esql/public'; import { fetchFieldsFromESQL } from '@kbn/text-based-editor'; -import { getIndexPatternFromESQLQuery } from '@kbn/esql-utils'; +import { getESQLAdHocDataview } from '@kbn/esql-utils'; import type { AggregateQuery } from '@kbn/es-query'; import { parseDuration } from '@kbn/alerting-plugin/common'; import { @@ -39,7 +38,7 @@ import { rowToDocument, toEsQueryHits, transformDatatableToEsqlTable } from '../ export const EsqlQueryExpression: React.FC< RuleTypeParamsExpressionProps, EsQueryRuleMetaData> > = ({ ruleParams, setRuleParams, setRuleProperty, errors }) => { - const { expressions, http, fieldFormats, isServerless } = useTriggerUiActionServices(); + const { expressions, http, fieldFormats, isServerless, dataViews } = useTriggerUiActionServices(); const { esqlQuery, timeWindowSize, timeWindowUnit, timeField } = ruleParams; const [currentRuleParams, setCurrentRuleParams] = useState< @@ -63,7 +62,7 @@ export const EsqlQueryExpression: React.FC< }); const [query, setQuery] = useState({ esql: '' }); const [timeFieldOptions, setTimeFieldOptions] = useState([firstFieldOption]); - const [detectTimestamp, setDetectTimestamp] = useState(false); + const [detectedTimestamp, setDetectedTimestamp] = useState(undefined); const [isLoading, setIsLoading] = useState(false); const setParam = useCallback( @@ -161,19 +160,18 @@ export const EsqlQueryExpression: React.FC< ]); const refreshTimeFields = async (q: AggregateQuery) => { - let hasTimestamp = false; - const indexPattern: string = getIndexPatternFromESQLQuery(get(q, 'esql')); + const esqlDataView = await getESQLAdHocDataview(q.esql, dataViews); + const indexPattern: string = esqlDataView.getIndexPattern(); const currentEsFields = await getFields(http, [indexPattern]); const timeFields = getTimeFieldOptions(currentEsFields); setTimeFieldOptions([firstFieldOption, ...timeFields]); - const timestampField = timeFields.find((field) => field.value === '@timestamp'); + const timestampField = esqlDataView.timeFieldName; if (timestampField) { - setParam('timeField', timestampField.value); - hasTimestamp = true; + setParam('timeField', timestampField); } - setDetectTimestamp(hasTimestamp); + setDetectedTimestamp(timestampField); }; return ( @@ -199,7 +197,7 @@ export const EsqlQueryExpression: React.FC< expandCodeEditor={() => true} isCodeEditorExpanded={true} onTextLangQuerySubmit={async () => {}} - detectTimestamp={detectTimestamp} + detectedTimestamp={detectedTimestamp} hideMinimizeButton={true} hideRunQueryText={true} isLoading={isLoading} diff --git a/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/expression.test.tsx b/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/expression.test.tsx index 0e49fabea2ca5..64d075b7ba723 100644 --- a/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/expression.test.tsx +++ b/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/expression.test.tsx @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - +import type { DataView } from '@kbn/data-views-plugin/public'; import { mountWithIntl } from '@kbn/test-jest-helpers'; import 'brace'; import React, { useState } from 'react'; @@ -154,6 +154,12 @@ const dataViewEditorMock = dataViewEditorPluginMock.createStartContract(); (dataViewsMock.getIds as jest.Mock) = jest.fn().mockImplementation(() => Promise.resolve([])); dataViewsMock.getDefaultDataView = jest.fn(() => Promise.resolve(null)); dataViewsMock.get = jest.fn(); +dataViewsMock.create.mockResolvedValue({ + title: 'test-index', + type: 'esql', + id: 'test-index', + getIndexPattern: () => 'test-index', +} as DataView); (dataMock.query.savedQueries.getSavedQuery as jest.Mock).mockImplementation(() => Promise.resolve(savedQueryMock) ); diff --git a/x-pack/plugins/stack_alerts/server/types.ts b/x-pack/plugins/stack_alerts/server/types.ts index 83e08b05f7634..ce148fb8c0434 100644 --- a/x-pack/plugins/stack_alerts/server/types.ts +++ b/x-pack/plugins/stack_alerts/server/types.ts @@ -15,7 +15,7 @@ export type { RuleExecutorOptions, RuleTypeParams, } from '@kbn/alerting-plugin/server'; -import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; // this plugin's dependendencies export interface StackAlertsDeps { diff --git a/x-pack/plugins/stack_connectors/common/sentinelone/constants.ts b/x-pack/plugins/stack_connectors/common/sentinelone/constants.ts index 1c89493956531..c72feb402ec37 100644 --- a/x-pack/plugins/stack_connectors/common/sentinelone/constants.ts +++ b/x-pack/plugins/stack_connectors/common/sentinelone/constants.ts @@ -17,6 +17,7 @@ export enum SUB_ACTION { GET_REMOTE_SCRIPTS = 'getRemoteScripts', GET_REMOTE_SCRIPT_STATUS = 'getRemoteScriptStatus', GET_REMOTE_SCRIPT_RESULTS = 'getRemoteScriptResults', + DOWNLOAD_REMOTE_SCRIPT_RESULTS = 'downloadRemoteScriptResults', FETCH_AGENT_FILES = 'fetchAgentFiles', DOWNLOAD_AGENT_FILE = 'downloadAgentFile', GET_ACTIVITIES = 'getActivities', diff --git a/x-pack/plugins/stack_connectors/common/sentinelone/schema.ts b/x-pack/plugins/stack_connectors/common/sentinelone/schema.ts index 80f86a5c05ad8..431d3be6d059b 100644 --- a/x-pack/plugins/stack_connectors/common/sentinelone/schema.ts +++ b/x-pack/plugins/stack_connectors/common/sentinelone/schema.ts @@ -375,6 +375,24 @@ export const SentinelOneExecuteScriptResponseSchema = schema.object({ ), }); +export const SentinelOneGetRemoteScriptResultsParamsSchema = schema.object({ + taskIds: schema.arrayOf(schema.string()), +}); + +export const SentinelOneGetRemoteScriptResultsResponseSchema = schema.object( + { + errors: schema.nullable(schema.arrayOf(schema.object({ type: schema.string() }))), + data: schema.any(), + }, + { unknowns: 'allow' } +); + +export const SentinelOneDownloadRemoteScriptResultsParamsSchema = schema.object({ + taskId: schema.string({ minLength: 1 }), +}); + +export const SentinelOneDownloadRemoteScriptResultsResponseSchema = schema.stream(); + export const SentinelOneGetRemoteScriptStatusParamsSchema = schema.object( { parentTaskId: schema.string(), @@ -388,39 +406,7 @@ export const SentinelOneGetRemoteScriptStatusResponseSchema = schema.object({ nextCursor: schema.nullable(schema.string()), }), errors: schema.nullable(schema.arrayOf(schema.object({ type: schema.string() }))), - data: schema.arrayOf( - schema.object( - { - agentIsDecommissioned: schema.nullable(schema.boolean()), - agentComputerName: schema.nullable(schema.string()), - status: schema.nullable(schema.string()), - groupName: schema.nullable(schema.string()), - initiatedById: schema.nullable(schema.string()), - parentTaskId: schema.nullable(schema.string()), - updatedAt: schema.nullable(schema.string()), - createdAt: schema.nullable(schema.string()), - agentIsActive: schema.nullable(schema.boolean()), - agentOsType: schema.nullable(schema.string()), - agentMachineType: schema.nullable(schema.string()), - id: schema.nullable(schema.string()), - siteName: schema.nullable(schema.string()), - detailedStatus: schema.nullable(schema.string()), - siteId: schema.nullable(schema.string()), - scriptResultsSignature: schema.nullable(schema.nullable(schema.string())), - initiatedBy: schema.nullable(schema.string()), - accountName: schema.nullable(schema.string()), - groupId: schema.nullable(schema.string()), - agentUuid: schema.nullable(schema.string()), - accountId: schema.nullable(schema.string()), - type: schema.nullable(schema.string()), - scriptResultsPath: schema.nullable(schema.string()), - scriptResultsBucket: schema.nullable(schema.string()), - description: schema.nullable(schema.string()), - agentId: schema.nullable(schema.string()), - }, - { unknowns: 'allow' } - ) - ), + data: schema.arrayOf(schema.mapOf(schema.string(), schema.any())), }); export const SentinelOneBaseFilterSchema = schema.object({ @@ -576,18 +562,10 @@ export const SentinelOneBaseFilterSchema = schema.object({ alertIds: AlertIds, }); -export const SentinelOneKillProcessParamsSchema = SentinelOneBaseFilterSchema.extends({ - processName: schema.string(), -}); - export const SentinelOneIsolateHostParamsSchema = SentinelOneBaseFilterSchema; export const SentinelOneGetAgentsParamsSchema = SentinelOneBaseFilterSchema; -export const SentinelOneGetRemoteScriptsStatusParams = schema.object({ - parentTaskId: schema.string(), -}); - export const SentinelOneIsolateHostSchema = schema.object({ subAction: schema.literal(SUB_ACTION.ISOLATE_HOST), subActionParams: SentinelOneIsolateHostParamsSchema, diff --git a/x-pack/plugins/stack_connectors/common/sentinelone/types.ts b/x-pack/plugins/stack_connectors/common/sentinelone/types.ts index 83cdc74925341..bb5705d30f7c5 100644 --- a/x-pack/plugins/stack_connectors/common/sentinelone/types.ts +++ b/x-pack/plugins/stack_connectors/common/sentinelone/types.ts @@ -14,7 +14,7 @@ import { SentinelOneGetAgentsResponseSchema, SentinelOneGetRemoteScriptsParamsSchema, SentinelOneGetRemoteScriptsResponseSchema, - SentinelOneGetRemoteScriptsStatusParams, + SentinelOneGetRemoteScriptStatusParamsSchema, SentinelOneIsolateHostParamsSchema, SentinelOneSecretsSchema, SentinelOneActionParamsSchema, @@ -24,8 +24,23 @@ import { SentinelOneGetActivitiesParamsSchema, SentinelOneGetActivitiesResponseSchema, SentinelOneExecuteScriptResponseSchema, + SentinelOneGetRemoteScriptResultsParamsSchema, + SentinelOneDownloadRemoteScriptResultsParamsSchema, } from './schema'; +interface SentinelOnePagination { + pagination: { + totalItems: number; + nextCursor?: string; + }; +} + +interface SentinelOneErrors { + errors?: string[]; +} + +export type SentinelOneOsType = 'linux' | 'macos' | 'windows'; + export type SentinelOneConfig = TypeOf; export type SentinelOneSecrets = TypeOf; @@ -39,8 +54,79 @@ export type SentinelOneExecuteScriptResponse = TypeOf< typeof SentinelOneExecuteScriptResponseSchema >; +export interface SentinelOneRemoteScriptExecutionStatus { + accountId: string; + accountName: string; + agentComputerName: string; + agentId: string; + agentIsActive: boolean; + agentIsDecommissioned: boolean; + agentMachineType: string; + agentOsType: SentinelOneOsType; + agentUuid: string; + createdAt: string; + description?: string; + detailedStatus?: string; + groupId: string; + groupName: string; + /** The `id` can be used to retrieve the script results file from sentinleone */ + id: string; + initiatedBy: string; + initiatedById: string; + parentTaskId: string; + /** `scriptResultsSignature` will be present only when there is a file with results */ + scriptResultsSignature?: string; + siteId: string; + siteName: string; + status: + | 'canceled' + | 'completed' + | 'created' + | 'expired' + | 'failed' + | 'in_progress' + | 'partially_completed' + | 'pending' + | 'pending_user_action' + | 'scheduled'; + statusCode?: string; + statusDescription: string; + type: string; + updatedAt: string; +} + export type SentinelOneGetRemoteScriptStatusParams = TypeOf< - typeof SentinelOneGetRemoteScriptsStatusParams + typeof SentinelOneGetRemoteScriptStatusParamsSchema +>; + +export interface SentinelOneGetRemoteScriptStatusApiResponse + extends SentinelOnePagination, + SentinelOneErrors { + data: SentinelOneRemoteScriptExecutionStatus[]; +} + +export type SentinelOneGetRemoteScriptResultsParams = TypeOf< + typeof SentinelOneGetRemoteScriptResultsParamsSchema +>; + +export interface SentinelOneGetRemoteScriptResults { + download_links: Array<{ + downloadUrl: string; + fileName: string; + taskId: string; + }>; + errors?: Array<{ + taskId: string; + errorString: string; + }>; +} + +export interface SentinelOneGetRemoteScriptResultsApiResponse extends SentinelOneErrors { + data: SentinelOneGetRemoteScriptResults; +} + +export type SentinelOneDownloadRemoteScriptResultsParams = TypeOf< + typeof SentinelOneDownloadRemoteScriptResultsParamsSchema >; export type SentinelOneGetRemoteScriptsParams = TypeOf< diff --git a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/mocks.ts b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/mocks.ts index 3177cb1f3cb4f..b53ba30673198 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/mocks.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/mocks.ts @@ -24,6 +24,7 @@ import { SentinelOneConfig, SentinelOneFetchAgentFilesResponse, SentinelOneGetAgentsResponse, + SentinelOneGetRemoteScriptResults, SentinelOneSecrets, } from '../../../common/sentinelone/types'; @@ -132,6 +133,18 @@ const createAgentDetailsMock = ( return merge(details, overrides); }; +const createRemoteScriptResultsMock = (): SentinelOneGetRemoteScriptResults => { + return { + download_links: [ + { + downloadUrl: 'https://remote/script/results/download', + fileName: 'some_file_name', + taskId: 'task-123', + }, + ], + }; +}; + const createGetAgentsApiResponseMock = (): SentinelOneGetAgentsResponse => { return { pagination: { @@ -163,6 +176,10 @@ class SentinelOneConnectorTestClass extends SentinelOneConnector { data: { success: true }, } as SentinelOneFetchAgentFilesResponse, downloadAgentFileApiResponse: Readable.from(['test']), + getRemoteScriptResults: { + data: createRemoteScriptResultsMock(), + }, + downloadRemoteScriptResults: Readable.from(['test']), }; public requestSpy = jest.fn(async ({ url }: SubActionRequestParams) => { @@ -179,6 +196,14 @@ class SentinelOneConnectorTestClass extends SentinelOneConnector { return sentinelOneConnectorMocks.createAxiosResponse( this.mockResponses.downloadAgentFileApiResponse ); + } else if (/remote-scripts\/fetch-files/.test(url)) { + return sentinelOneConnectorMocks.createAxiosResponse( + this.mockResponses.getRemoteScriptResults + ); + } else if (/remote\/script\/results\/download/.test(url)) { + return sentinelOneConnectorMocks.createAxiosResponse( + this.mockResponses.downloadRemoteScriptResults + ); } return response; @@ -213,4 +238,5 @@ export const sentinelOneConnectorMocks = Object.freeze({ createAxiosResponse: createAxiosResponseMock, createGetAgentsApiResponse: createGetAgentsApiResponseMock, createAgentDetails: createAgentDetailsMock, + createRemoteScriptResults: createRemoteScriptResultsMock, }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.test.ts index 3dc41d461670c..675cf13f18516 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.test.ts @@ -120,4 +120,31 @@ describe('SentinelOne Connector', () => { ); }); }); + + describe('#downloadRemoteScriptResults()', () => { + it('should call SentinelOne api to retrieve task results', async () => { + await connectorInstance.downloadRemoteScriptResults({ taskId: 'task-123' }); + + expect(connectorInstance.requestSpy).toHaveBeenCalledWith( + expect.objectContaining({ + url: `${connectorInstance.constructorParams.config.url}${API_PATH}/remote-scripts/fetch-files`, + data: { data: { taskIds: ['task-123'] } }, + }) + ); + }); + + it('should error if task does not have a download url', async () => { + connectorInstance.mockResponses.getRemoteScriptResults.data.download_links = []; + + await expect( + connectorInstance.downloadRemoteScriptResults({ taskId: 'task-123' }) + ).rejects.toThrow('Download URL for script results of task id [task-123] not found'); + }); + + it('should return a Stream for downloading the file', async () => { + await expect( + connectorInstance.downloadRemoteScriptResults({ taskId: 'task-123' }) + ).resolves.toEqual(connectorInstance.mockResponses.downloadRemoteScriptResults); + }); + }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.ts b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.ts index 028e6ad1a7643..803a735ca55af 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.ts @@ -8,6 +8,7 @@ import { ServiceParams, SubActionConnector } from '@kbn/actions-plugin/server'; import type { AxiosError } from 'axios'; import { SubActionRequestParams } from '@kbn/actions-plugin/server/sub_action_framework/types'; +import { Stream } from 'stream'; import type { SentinelOneConfig, SentinelOneSecrets, @@ -37,12 +38,20 @@ import { SentinelOneDownloadAgentFileResponseSchema, SentinelOneGetActivitiesParamsSchema, SentinelOneGetActivitiesResponseSchema, + SentinelOneGetRemoteScriptResultsResponseSchema, + SentinelOneGetRemoteScriptResultsParamsSchema, + SentinelOneDownloadRemoteScriptResultsParamsSchema, + SentinelOneDownloadRemoteScriptResultsResponseSchema, } from '../../../common/sentinelone/schema'; import { SUB_ACTION } from '../../../common/sentinelone/constants'; import { SentinelOneFetchAgentFilesParams, SentinelOneDownloadAgentFileParams, SentinelOneGetActivitiesParams, + SentinelOneGetRemoteScriptResultsParams, + SentinelOneDownloadRemoteScriptResultsParams, + SentinelOneGetRemoteScriptResultsApiResponse, + SentinelOneGetRemoteScriptStatusApiResponse, } from '../../../common/sentinelone/types'; export const API_MAX_RESULTS = 1000; @@ -59,6 +68,7 @@ export class SentinelOneConnector extends SubActionConnector< remoteScripts: string; remoteScriptStatus: string; remoteScriptsExecute: string; + remoteScriptsResults: string; activities: string; }; @@ -71,6 +81,7 @@ export class SentinelOneConnector extends SubActionConnector< remoteScripts: `${this.config.url}${API_PATH}/remote-scripts`, remoteScriptStatus: `${this.config.url}${API_PATH}/remote-scripts/status`, remoteScriptsExecute: `${this.config.url}${API_PATH}/remote-scripts/execute`, + remoteScriptsResults: `${this.config.url}${API_PATH}/remote-scripts/fetch-files`, agents: `${this.config.url}${API_PATH}/agents`, activities: `${this.config.url}${API_PATH}/activities`, }; @@ -109,6 +120,18 @@ export class SentinelOneConnector extends SubActionConnector< schema: SentinelOneGetRemoteScriptStatusParamsSchema, }); + this.registerSubAction({ + name: SUB_ACTION.GET_REMOTE_SCRIPT_RESULTS, + method: 'getRemoteScriptResults', + schema: SentinelOneGetRemoteScriptResultsParamsSchema, + }); + + this.registerSubAction({ + name: SUB_ACTION.DOWNLOAD_REMOTE_SCRIPT_RESULTS, + method: 'downloadRemoteScriptResults', + schema: SentinelOneDownloadRemoteScriptResultsParamsSchema, + }); + this.registerSubAction({ name: SUB_ACTION.GET_AGENTS, method: 'getAgents', @@ -269,14 +292,59 @@ export class SentinelOneConnector extends SubActionConnector< }); } - public async getRemoteScriptStatus(payload: SentinelOneGetRemoteScriptStatusParams) { + public async getRemoteScriptStatus( + payload: SentinelOneGetRemoteScriptStatusParams + ): Promise { return this.sentinelOneApiRequest({ url: this.urls.remoteScriptStatus, params: { parent_task_id: payload.parentTaskId, }, responseSchema: SentinelOneGetRemoteScriptStatusResponseSchema, + }) as unknown as SentinelOneGetRemoteScriptStatusApiResponse; + } + + public async getRemoteScriptResults({ + taskIds, + }: SentinelOneGetRemoteScriptResultsParams): Promise { + return this.sentinelOneApiRequest({ + url: this.urls.remoteScriptsResults, + method: 'post', + data: { data: { taskIds } }, + responseSchema: SentinelOneGetRemoteScriptResultsResponseSchema, + }) as unknown as SentinelOneGetRemoteScriptResultsApiResponse; + } + + public async downloadRemoteScriptResults({ + taskId, + }: SentinelOneDownloadRemoteScriptResultsParams): Promise { + const scriptResultsInfo = await this.getRemoteScriptResults({ taskIds: [taskId] }); + + this.logger.debug( + () => `script results for taskId [${taskId}]:\n${JSON.stringify(scriptResultsInfo)}` + ); + + let fileUrl: string = ''; + + for (const downloadLinkInfo of scriptResultsInfo.data.download_links) { + if (downloadLinkInfo.taskId === taskId) { + fileUrl = downloadLinkInfo.downloadUrl; + break; + } + } + + if (!fileUrl) { + throw new Error(`Download URL for script results of task id [${taskId}] not found`); + } + + const downloadConnection = await this.request({ + url: fileUrl, + method: 'get', + responseType: 'stream', + responseSchema: SentinelOneDownloadRemoteScriptResultsResponseSchema, }); + + return downloadConnection.data; } private async sentinelOneApiRequest( diff --git a/x-pack/plugins/task_manager/server/kibana_discovery_service/delete_inactive_nodes_task.test.ts b/x-pack/plugins/task_manager/server/kibana_discovery_service/delete_inactive_nodes_task.test.ts new file mode 100644 index 0000000000000..ac2f2ebec347b --- /dev/null +++ b/x-pack/plugins/task_manager/server/kibana_discovery_service/delete_inactive_nodes_task.test.ts @@ -0,0 +1,143 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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, + savedObjectsRepositoryMock, + savedObjectsServiceMock, +} from '@kbn/core/server/mocks'; +import { CLEANUP_INTERVAL, taskRunner } from './delete_inactive_nodes_task'; +import { BackgroundTaskNode } from '../saved_objects/schemas/background_task_node'; +import { + SavedObjectsFindResponse, + SavedObjectsFindResult, +} from '@kbn/core-saved-objects-api-server'; +import { BACKGROUND_TASK_NODE_SO_NAME } from '../saved_objects'; + +const currentNode = 'current-node-id'; +const now = '2024-08-10T10:00:00.000Z'; + +const createNodeRecord = (id: string = '1', lastSeen: string = now): BackgroundTaskNode => ({ + id, + last_seen: lastSeen, +}); + +const createFindSO = ( + id: string = currentNode, + lastSeen: string = now +): SavedObjectsFindResult => ({ + attributes: createNodeRecord(id, lastSeen), + id: `${BACKGROUND_TASK_NODE_SO_NAME}:${id}`, + namespaces: ['default'], + references: [], + score: 1, + type: BACKGROUND_TASK_NODE_SO_NAME, + updated_at: new Date().toDateString(), + version: '1', +}); + +const createFindResponse = ( + soList: Array> +): SavedObjectsFindResponse => ({ + total: 1, + per_page: 100, + page: 1, + saved_objects: soList, +}); + +describe('Delete inactive background task nodes', () => { + const logger = mockLogger(); + const coreSetup = coreMock.createSetup(); + + const savedObjectsRepository = savedObjectsRepositoryMock.create(); + + coreSetup.getStartServices.mockResolvedValue([ + { + ...coreMock.createStart(), + savedObjects: { + ...savedObjectsServiceMock.createStartContract(), + createInternalRepository: () => savedObjectsRepository, + }, + }, + coreMock.createSetup(), + {}, + ]); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('deletes the inactive nodes', async () => { + savedObjectsRepository.find.mockResolvedValue( + createFindResponse([ + createFindSO('123', '10.10.2024'), + createFindSO('456', '10.10.2024'), + createFindSO('789', '10.10.2024'), + ]) + ); + + const runner = taskRunner(logger, coreSetup.getStartServices)(); + const result = await runner.run(); + + expect(savedObjectsRepository.bulkDelete).toHaveBeenCalledWith( + [ + { id: '123', type: 'background-task-node' }, + { id: '456', type: 'background-task-node' }, + { id: '789', type: 'background-task-node' }, + ], + { force: true, refresh: false } + ); + + expect(logger.debug).toHaveBeenCalledWith( + 'Inactive Kibana nodes: 123,456,789, have been successfully deleted' + ); + + expect(result).toEqual({ + state: {}, + schedule: { + interval: CLEANUP_INTERVAL, + }, + }); + }); + + it("skips delete when there isn't any inactive node", async () => { + savedObjectsRepository.find.mockResolvedValue(createFindResponse([])); + + const runner = taskRunner(logger, coreSetup.getStartServices)(); + const result = await runner.run(); + + expect(savedObjectsRepository.bulkDelete).not.toHaveBeenCalled(); + + expect(logger.info).not.toHaveBeenCalled(); + + expect(result).toEqual({ + state: {}, + schedule: { + interval: CLEANUP_INTERVAL, + }, + }); + }); + + it('schedules the next run even when there is an error', async () => { + savedObjectsRepository.find.mockRejectedValueOnce(new Error('foo')); + + const runner = taskRunner(logger, coreSetup.getStartServices)(); + const result = await runner.run(); + + expect(savedObjectsRepository.bulkDelete).not.toHaveBeenCalled(); + + expect(logger.error).toHaveBeenCalledWith('Deleting inactive nodes failed. Error: foo '); + + expect(result).toEqual({ + state: {}, + schedule: { + interval: CLEANUP_INTERVAL, + }, + }); + }); +}); diff --git a/x-pack/plugins/task_manager/server/kibana_discovery_service/delete_inactive_nodes_task.ts b/x-pack/plugins/task_manager/server/kibana_discovery_service/delete_inactive_nodes_task.ts new file mode 100644 index 0000000000000..f5d7204d739da --- /dev/null +++ b/x-pack/plugins/task_manager/server/kibana_discovery_service/delete_inactive_nodes_task.ts @@ -0,0 +1,107 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { TaskScheduling } from '../task_scheduling'; +import { TaskTypeDictionary } from '../task_type_dictionary'; +import { BackgroundTaskNode } from '../saved_objects/schemas/background_task_node'; +import { BACKGROUND_TASK_NODE_SO_NAME } from '../saved_objects'; +import { TaskManagerStartContract } from '..'; + +export const TASK_ID = 'delete_inactive_background_task_nodes'; +const TASK_TYPE = `task_manager:${TASK_ID}`; + +export const CLEANUP_INTERVAL = '1m'; +export const CLEANUP_LOOKBACK = '5m'; + +export async function scheduleDeleteInactiveNodesTaskDefinition( + logger: Logger, + taskScheduling: TaskScheduling +) { + try { + await taskScheduling.ensureScheduled({ + id: TASK_ID, + taskType: TASK_TYPE, + schedule: { + interval: CLEANUP_INTERVAL, + }, + state: {}, + params: {}, + }); + } catch (e) { + logger.error(`Error scheduling ${TASK_ID} task, received ${e.message}`); + } +} + +export function registerDeleteInactiveNodesTaskDefinition( + logger: Logger, + coreStartServices: () => Promise<[CoreStart, TaskManagerStartContract, unknown]>, + taskTypeDictionary: TaskTypeDictionary +) { + taskTypeDictionary.registerTaskDefinitions({ + [TASK_TYPE]: { + title: 'Remove inactive background task nodes', + createTaskRunner: taskRunner(logger, coreStartServices), + }, + }); +} + +export function taskRunner( + logger: Logger, + coreStartServices: () => Promise<[CoreStart, TaskManagerStartContract, unknown]> +) { + return () => { + return { + async run() { + try { + const [{ savedObjects }] = await coreStartServices(); + const savedObjectsRepository = savedObjects.createInternalRepository([ + BACKGROUND_TASK_NODE_SO_NAME, + ]); + + const { saved_objects: inactiveNodes } = + await savedObjectsRepository.find({ + type: BACKGROUND_TASK_NODE_SO_NAME, + perPage: 100, + page: 1, + filter: `${BACKGROUND_TASK_NODE_SO_NAME}.attributes.last_seen < now-${CLEANUP_LOOKBACK}`, + }); + + if (inactiveNodes.length > 0) { + const nodesToDelete = inactiveNodes.map((node) => ({ + type: BACKGROUND_TASK_NODE_SO_NAME, + id: node.attributes.id, + })); + await savedObjectsRepository.bulkDelete(nodesToDelete, { + force: true, + refresh: false, + }); + + const deletedNodes = nodesToDelete.map((node) => node.id); + logger.debug(`Inactive Kibana nodes: ${deletedNodes}, have been successfully deleted`); + } + + return { + state: {}, + schedule: { + interval: CLEANUP_INTERVAL, + }, + }; + } catch (e) { + logger.error(`Deleting inactive nodes failed. Error: ${e.message} `); + return { + state: {}, + schedule: { + interval: CLEANUP_INTERVAL, + }, + }; + } + }, + }; + }; +} diff --git a/x-pack/plugins/security_solution_ess/public/common/hooks/__mocks__/use_variation.ts b/x-pack/plugins/task_manager/server/kibana_discovery_service/index.ts similarity index 78% rename from x-pack/plugins/security_solution_ess/public/common/hooks/__mocks__/use_variation.ts rename to x-pack/plugins/task_manager/server/kibana_discovery_service/index.ts index 3babc2c3c5f94..f055400ddfefc 100644 --- a/x-pack/plugins/security_solution_ess/public/common/hooks/__mocks__/use_variation.ts +++ b/x-pack/plugins/task_manager/server/kibana_discovery_service/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export const useVariation = jest.fn(); +export { KibanaDiscoveryService } from './kibana_discovery_service'; diff --git a/x-pack/plugins/task_manager/server/kibana_discovery_service/kibana_discovery_service.test.ts b/x-pack/plugins/task_manager/server/kibana_discovery_service/kibana_discovery_service.test.ts new file mode 100644 index 0000000000000..c82618d34bf8a --- /dev/null +++ b/x-pack/plugins/task_manager/server/kibana_discovery_service/kibana_discovery_service.test.ts @@ -0,0 +1,244 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { savedObjectsRepositoryMock, loggingSystemMock } from '@kbn/core/server/mocks'; +import { + KibanaDiscoveryService, + DISCOVERY_INTERVAL, + ACTIVE_NODES_LOOK_BACK, +} from './kibana_discovery_service'; +import { BACKGROUND_TASK_NODE_SO_NAME } from '../saved_objects'; +import { + SavedObjectsBulkDeleteResponse, + SavedObjectsFindResponse, + SavedObjectsFindResult, + SavedObjectsUpdateResponse, +} from '@kbn/core/server'; + +import { BackgroundTaskNode } from '../saved_objects/schemas/background_task_node'; + +const currentNode = 'current-node-id'; +const now = '2024-08-10T10:00:00.000Z'; + +const createNodeRecord = (id: string = '1', lastSeen: string = now): BackgroundTaskNode => ({ + id, + last_seen: lastSeen, +}); + +const createFindSO = ( + id: string = currentNode, + lastSeen: string = now +): SavedObjectsFindResult => ({ + attributes: createNodeRecord(id, lastSeen), + id: `${BACKGROUND_TASK_NODE_SO_NAME}:${id}`, + namespaces: ['default'], + references: [], + score: 1, + type: BACKGROUND_TASK_NODE_SO_NAME, + updated_at: new Date().toDateString(), + version: '1', +}); + +const createFindResponse = ( + soList: Array> +): SavedObjectsFindResponse => ({ + total: 1, + per_page: 10000, + page: 1, + saved_objects: soList, +}); + +describe('KibanaDiscoveryService', () => { + const savedObjectsRepository = savedObjectsRepositoryMock.create(); + const logger = loggingSystemMock.createLogger(); + + savedObjectsRepository.find.mockResolvedValue(createFindResponse([])); + savedObjectsRepository.update.mockResolvedValue({} as SavedObjectsUpdateResponse); + savedObjectsRepository.bulkDelete.mockResolvedValue({} as SavedObjectsBulkDeleteResponse); + + beforeEach(() => { + jest.useFakeTimers(); + jest.spyOn(global, 'setTimeout'); + jest.setSystemTime(new Date(now)); + }); + + afterEach(() => { + jest.useRealTimers(); + jest.clearAllMocks(); + }); + + describe('Discovery', () => { + it('starts successfully', async () => { + const kibanaDiscoveryService = new KibanaDiscoveryService({ + savedObjectsRepository, + logger, + currentNode, + }); + await kibanaDiscoveryService.start(); + + expect(savedObjectsRepository.update).toHaveBeenCalledTimes(1); + expect(savedObjectsRepository.update).toHaveBeenCalledWith( + BACKGROUND_TASK_NODE_SO_NAME, + currentNode, + { id: 'current-node-id', last_seen: '2024-08-10T10:00:00.000Z' }, + { upsert: { id: 'current-node-id', last_seen: '2024-08-10T10:00:00.000Z' }, refresh: false } + ); + expect(savedObjectsRepository.find).not.toHaveBeenCalled(); + expect(savedObjectsRepository.bulkDelete).not.toHaveBeenCalled(); + + expect(logger.info).toHaveBeenCalledTimes(1); + expect(logger.warn).not.toHaveBeenCalled(); + expect(logger.error).not.toHaveBeenCalled(); + expect(logger.info).toHaveBeenCalledWith('Kibana Discovery Service has been started'); + expect(kibanaDiscoveryService.isStarted()).toBe(true); + }); + + it('does not start multiple times', async () => { + const kibanaDiscoveryService = new KibanaDiscoveryService({ + savedObjectsRepository, + logger, + currentNode, + }); + await kibanaDiscoveryService.start(); + await kibanaDiscoveryService.start(); + + expect(logger.info).toHaveBeenCalledTimes(1); + expect(logger.warn).toHaveBeenCalledTimes(1); + expect(logger.info).toHaveBeenCalledWith('Kibana Discovery Service has been started'); + expect(logger.warn).toHaveBeenCalledWith('Kibana Discovery Service has already been started'); + }); + + it('schedules discovery job', async () => { + savedObjectsRepository.find.mockResolvedValueOnce(createFindResponse([])); + const kibanaDiscoveryService = new KibanaDiscoveryService({ + savedObjectsRepository, + logger, + currentNode, + }); + await kibanaDiscoveryService.start(); + + expect(savedObjectsRepository.update).toHaveBeenCalledTimes(1); + + expect(setTimeout).toHaveBeenCalledTimes(1); + expect(setTimeout).toHaveBeenNthCalledWith(1, expect.any(Function), DISCOVERY_INTERVAL); + + jest.runOnlyPendingTimers(); + + expect(savedObjectsRepository.update).toHaveBeenCalledTimes(2); + }); + + it('reschedules when upsert fails on start', async () => { + savedObjectsRepository.update.mockRejectedValueOnce(new Error('foo')); + + const kibanaDiscoveryService = new KibanaDiscoveryService({ + savedObjectsRepository, + logger, + currentNode, + }); + await kibanaDiscoveryService.start(); + + expect(logger.error).toHaveBeenCalledTimes(1); + expect(logger.error).toHaveBeenCalledWith( + "Kibana Discovery Service couldn't be started and will be retried in 10000ms, error:foo" + ); + expect(logger.info).not.toHaveBeenCalled(); + expect(setTimeout).toHaveBeenCalledTimes(1); + expect(setTimeout).toHaveBeenNthCalledWith(1, expect.any(Function), DISCOVERY_INTERVAL); + }); + + it('reschedules when upsert fails after start', async () => { + savedObjectsRepository.update.mockResolvedValueOnce( + {} as SavedObjectsUpdateResponse + ); + + const kibanaDiscoveryService = new KibanaDiscoveryService({ + savedObjectsRepository, + logger, + currentNode, + }); + await kibanaDiscoveryService.start(); + + expect(savedObjectsRepository.update).toHaveBeenCalledTimes(1); + expect(logger.error).not.toHaveBeenCalled(); + expect(logger.info).toHaveBeenCalledWith('Kibana Discovery Service has been started'); + expect(kibanaDiscoveryService.isStarted()).toBe(true); + expect(setTimeout).toHaveBeenCalledTimes(1); + expect(setTimeout).toHaveBeenNthCalledWith(1, expect.any(Function), DISCOVERY_INTERVAL); + + savedObjectsRepository.update.mockRejectedValueOnce(new Error('foo')); + + await jest.advanceTimersByTimeAsync(15000); + + expect(savedObjectsRepository.update).toHaveBeenCalledTimes(2); + expect(setTimeout).toHaveBeenCalledTimes(2); + expect(setTimeout).toHaveBeenNthCalledWith(2, expect.any(Function), DISCOVERY_INTERVAL); + expect(logger.error).toHaveBeenCalledTimes(1); + expect(logger.error).toHaveBeenCalledWith( + "Kibana Discovery Service couldn't update this node's last_seen timestamp. id: current-node-id, last_seen: 2024-08-10T10:00:10.000Z, error:foo" + ); + }); + }); + + describe('getActiveKibanaNodes', () => { + const mockActiveNodes = [createFindSO('456', '10.10.2024')]; + savedObjectsRepository.find.mockResolvedValueOnce(createFindResponse(mockActiveNodes)); + + it('returns the active kibana nodes', async () => { + const kibanaDiscoveryService = new KibanaDiscoveryService({ + savedObjectsRepository, + logger, + currentNode, + }); + + const activeNodes = await kibanaDiscoveryService.getActiveKibanaNodes(); + + expect(savedObjectsRepository.find).toHaveBeenCalledWith({ + filter: `${BACKGROUND_TASK_NODE_SO_NAME}.attributes.last_seen > now-${ACTIVE_NODES_LOOK_BACK}`, + page: 1, + perPage: 10000, + type: BACKGROUND_TASK_NODE_SO_NAME, + }); + expect(activeNodes).toEqual(mockActiveNodes); + }); + }); + + describe('deleteCurrentNode', () => { + it('deletes the current kibana node SO', async () => { + savedObjectsRepository.delete.mockResolvedValueOnce(200); + + const kibanaDiscoveryService = new KibanaDiscoveryService({ + savedObjectsRepository, + logger, + currentNode, + }); + + await kibanaDiscoveryService.deleteCurrentNode(); + + expect(savedObjectsRepository.delete).toHaveBeenCalledWith( + BACKGROUND_TASK_NODE_SO_NAME, + 'current-node-id' + ); + + expect(logger.info).toHaveBeenCalledWith( + 'Removed this node from the Kibana Discovery Service' + ); + }); + + it('logs an error when failed', async () => { + savedObjectsRepository.delete.mockRejectedValue(new Error('bar')); + + const kibanaDiscoveryService = new KibanaDiscoveryService({ + savedObjectsRepository, + logger, + currentNode, + }); + + await kibanaDiscoveryService.deleteCurrentNode(); + + expect(logger.error).toHaveBeenCalledWith('Deleting current node has failed. error: bar'); + }); + }); +}); diff --git a/x-pack/plugins/task_manager/server/kibana_discovery_service/kibana_discovery_service.ts b/x-pack/plugins/task_manager/server/kibana_discovery_service/kibana_discovery_service.ts new file mode 100644 index 0000000000000..371950b3096c4 --- /dev/null +++ b/x-pack/plugins/task_manager/server/kibana_discovery_service/kibana_discovery_service.ts @@ -0,0 +1,110 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { ISavedObjectsRepository } from '@kbn/core/server'; +import { Logger } from '@kbn/core/server'; +import { BACKGROUND_TASK_NODE_SO_NAME } from '../saved_objects'; +import { BackgroundTaskNode } from '../saved_objects/schemas/background_task_node'; + +interface DiscoveryServiceParams { + currentNode: string; + savedObjectsRepository: ISavedObjectsRepository; + logger: Logger; +} + +interface DiscoveryServiceUpsertParams { + id: string; + lastSeen: string; +} + +export const DISCOVERY_INTERVAL = 1000 * 10; +export const ACTIVE_NODES_LOOK_BACK = '30s'; + +export class KibanaDiscoveryService { + private currentNode: string; + private started = false; + private savedObjectsRepository: ISavedObjectsRepository; + private logger: Logger; + + constructor({ currentNode, savedObjectsRepository, logger }: DiscoveryServiceParams) { + this.savedObjectsRepository = savedObjectsRepository; + this.logger = logger; + this.currentNode = currentNode; + } + + private async upsertCurrentNode({ id, lastSeen }: DiscoveryServiceUpsertParams) { + await this.savedObjectsRepository.update( + BACKGROUND_TASK_NODE_SO_NAME, + id, + { + id, + last_seen: lastSeen, + }, + { upsert: { id, last_seen: lastSeen }, refresh: false } + ); + } + + private async scheduleUpsertCurrentNode() { + const lastSeenDate = new Date(); + const lastSeen = lastSeenDate.toISOString(); + try { + await this.upsertCurrentNode({ id: this.currentNode, lastSeen }); + if (!this.started) { + this.logger.info('Kibana Discovery Service has been started'); + this.started = true; + } + } catch (e) { + if (!this.started) { + this.logger.error( + `Kibana Discovery Service couldn't be started and will be retried in ${DISCOVERY_INTERVAL}ms, error:${e.message}` + ); + } else { + this.logger.error( + `Kibana Discovery Service couldn't update this node's last_seen timestamp. id: ${this.currentNode}, last_seen: ${lastSeen}, error:${e.message}` + ); + } + } finally { + setTimeout( + async () => await this.scheduleUpsertCurrentNode(), + DISCOVERY_INTERVAL - (Date.now() - lastSeenDate.getTime()) + ); + } + } + + public isStarted() { + return this.started; + } + + public async start() { + if (!this.started) { + await this.scheduleUpsertCurrentNode(); + } else { + this.logger.warn('Kibana Discovery Service has already been started'); + } + } + + public async getActiveKibanaNodes() { + const { saved_objects: activeNodes } = + await this.savedObjectsRepository.find({ + type: BACKGROUND_TASK_NODE_SO_NAME, + perPage: 10000, + page: 1, + filter: `${BACKGROUND_TASK_NODE_SO_NAME}.attributes.last_seen > now-${ACTIVE_NODES_LOOK_BACK}`, + }); + + return activeNodes; + } + + public async deleteCurrentNode() { + try { + await this.savedObjectsRepository.delete(BACKGROUND_TASK_NODE_SO_NAME, this.currentNode); + this.logger.info('Removed this node from the Kibana Discovery Service'); + } catch (e) { + this.logger.error(`Deleting current node has failed. error: ${e.message}`); + } + } +} diff --git a/x-pack/plugins/task_manager/server/plugin.ts b/x-pack/plugins/task_manager/server/plugin.ts index c34fd1643c7eb..e931c58b579ac 100644 --- a/x-pack/plugins/task_manager/server/plugin.ts +++ b/x-pack/plugins/task_manager/server/plugin.ts @@ -18,11 +18,16 @@ import { ServiceStatusLevels, CoreStatus, } from '@kbn/core/server'; +import { + registerDeleteInactiveNodesTaskDefinition, + scheduleDeleteInactiveNodesTaskDefinition, +} from './kibana_discovery_service/delete_inactive_nodes_task'; +import { KibanaDiscoveryService } from './kibana_discovery_service'; import { TaskPollingLifecycle } from './polling_lifecycle'; import { TaskManagerConfig } from './config'; import { createInitialMiddleware, addMiddlewareToChain, Middleware } from './lib/middleware'; import { removeIfExists } from './lib/remove_if_exists'; -import { setupSavedObjects } from './saved_objects'; +import { setupSavedObjects, BACKGROUND_TASK_NODE_SO_NAME, TASK_SO_NAME } from './saved_objects'; import { TaskDefinitionRegistry, TaskTypeDictionary, REMOVED_TYPES } from './task_type_dictionary'; import { AggregationOpts, FetchResult, SearchOpts, TaskStore } from './task_store'; import { createManagedConfiguration } from './lib/create_managed_configuration'; @@ -92,6 +97,7 @@ export class TaskManagerPlugin private adHocTaskCounter: AdHocTaskCounter; private taskManagerMetricsCollector?: TaskManagerMetricsCollector; private nodeRoles: PluginInitializerContext['node']['roles']; + private kibanaDiscoveryService?: KibanaDiscoveryService; constructor(private readonly initContext: PluginInitializerContext) { this.initContext = initContext; @@ -110,7 +116,7 @@ export class TaskManagerPlugin } public setup( - core: CoreSetup, + core: CoreSetup, plugins: { usageCollection?: UsageCollectionSetup } ): TaskManagerSetupContract { this.elasticsearchAndSOAvailability$ = getElasticsearchAndSOAvailability(core.status.core$); @@ -197,6 +203,8 @@ export class TaskManagerPlugin ); } + registerDeleteInactiveNodesTaskDefinition(this.logger, core.getStartServices, this.definitions); + if (this.config.unsafe.exclude_task_types.length) { this.logger.warn( `Excluding task types from execution: ${this.config.unsafe.exclude_task_types.join(', ')}` @@ -229,7 +237,20 @@ export class TaskManagerPlugin executionContext, docLinks, }: CoreStart): TaskManagerStartContract { - const savedObjectsRepository = savedObjects.createInternalRepository(['task']); + const savedObjectsRepository = savedObjects.createInternalRepository([ + TASK_SO_NAME, + BACKGROUND_TASK_NODE_SO_NAME, + ]); + + this.kibanaDiscoveryService = new KibanaDiscoveryService({ + savedObjectsRepository, + logger: this.logger, + currentNode: this.taskManagerId!, + }); + + if (this.shouldRunBackgroundTasks) { + this.kibanaDiscoveryService.start().catch(() => {}); + } const serializer = savedObjects.createSerializer(); const taskStore = new TaskStore({ @@ -312,6 +333,8 @@ export class TaskManagerPlugin taskManagerId: taskStore.taskManagerId, }); + scheduleDeleteInactiveNodesTaskDefinition(this.logger, taskScheduling).catch(() => {}); + return { fetch: (opts: SearchOpts): Promise => taskStore.fetch(opts), aggregate: (opts: AggregationOpts): Promise> => @@ -334,6 +357,12 @@ export class TaskManagerPlugin bulkUpdateState: (...args) => taskScheduling.bulkUpdateState(...args), }; } + + public stop() { + if (this.kibanaDiscoveryService?.isStarted()) { + this.kibanaDiscoveryService.deleteCurrentNode().catch(() => {}); + } + } } export function getElasticsearchAndSOAvailability( diff --git a/x-pack/plugins/task_manager/server/saved_objects/index.ts b/x-pack/plugins/task_manager/server/saved_objects/index.ts index 68bc796d7aba3..dc1cd97677767 100644 --- a/x-pack/plugins/task_manager/server/saved_objects/index.ts +++ b/x-pack/plugins/task_manager/server/saved_objects/index.ts @@ -7,19 +7,22 @@ import type { SavedObjectsServiceSetup } from '@kbn/core/server'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { taskMappings } from './mappings'; +import { backgroundTaskNodeMapping, taskMappings } from './mappings'; import { getMigrations } from './migrations'; import { TaskManagerConfig } from '../config'; import { getOldestIdleActionTask } from '../queries/oldest_idle_action_task'; import { TASK_MANAGER_INDEX } from '../constants'; -import { taskModelVersions } from './model_versions'; +import { backgroundTaskNodeModelVersions, taskModelVersions } from './model_versions'; + +export const TASK_SO_NAME = 'task'; +export const BACKGROUND_TASK_NODE_SO_NAME = 'background-task-node'; export function setupSavedObjects( savedObjects: SavedObjectsServiceSetup, config: TaskManagerConfig ) { savedObjects.registerType({ - name: 'task', + name: TASK_SO_NAME, namespaceType: 'agnostic', hidden: true, convertToAliasScript: `ctx._id = ctx._source.type + ':' + ctx._id; ctx._source.remove("kibana")`, @@ -75,4 +78,13 @@ export function setupSavedObjects( }, modelVersions: taskModelVersions, }); + + savedObjects.registerType({ + name: BACKGROUND_TASK_NODE_SO_NAME, + namespaceType: 'agnostic', + hidden: true, + mappings: backgroundTaskNodeMapping, + indexPattern: TASK_MANAGER_INDEX, + modelVersions: backgroundTaskNodeModelVersions, + }); } diff --git a/x-pack/plugins/task_manager/server/saved_objects/mappings.ts b/x-pack/plugins/task_manager/server/saved_objects/mappings.ts index df38c78309e39..c0dc563a85157 100644 --- a/x-pack/plugins/task_manager/server/saved_objects/mappings.ts +++ b/x-pack/plugins/task_manager/server/saved_objects/mappings.ts @@ -64,3 +64,15 @@ export const taskMappings: SavedObjectsTypeMappingDefinition = { }, }, }; + +export const backgroundTaskNodeMapping: SavedObjectsTypeMappingDefinition = { + dynamic: false, + properties: { + id: { + type: 'keyword', + }, + last_seen: { + type: 'date', + }, + }, +}; diff --git a/x-pack/plugins/task_manager/server/saved_objects/model_versions/background_task_node_model_versions.ts b/x-pack/plugins/task_manager/server/saved_objects/model_versions/background_task_node_model_versions.ts new file mode 100644 index 0000000000000..73b38f2fc6191 --- /dev/null +++ b/x-pack/plugins/task_manager/server/saved_objects/model_versions/background_task_node_model_versions.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { SavedObjectsModelVersionMap } from '@kbn/core-saved-objects-server'; +import { backgroundTaskNodeSchemaV1 } from '../schemas/background_task_node'; + +export const backgroundTaskNodeModelVersions: SavedObjectsModelVersionMap = { + '1': { + changes: [], + schemas: { + create: backgroundTaskNodeSchemaV1, + }, + }, +}; diff --git a/x-pack/plugins/task_manager/server/saved_objects/model_versions/index.ts b/x-pack/plugins/task_manager/server/saved_objects/model_versions/index.ts index 9d84e528a3d39..237c15a53349f 100644 --- a/x-pack/plugins/task_manager/server/saved_objects/model_versions/index.ts +++ b/x-pack/plugins/task_manager/server/saved_objects/model_versions/index.ts @@ -6,3 +6,4 @@ */ export { taskModelVersions } from './task_model_versions'; +export { backgroundTaskNodeModelVersions } from './background_task_node_model_versions'; diff --git a/x-pack/plugins/task_manager/server/saved_objects/schemas/background_task_node.ts b/x-pack/plugins/task_manager/server/saved_objects/schemas/background_task_node.ts new file mode 100644 index 0000000000000..d28b7cadfb283 --- /dev/null +++ b/x-pack/plugins/task_manager/server/saved_objects/schemas/background_task_node.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema, TypeOf } from '@kbn/config-schema'; + +export const backgroundTaskNodeSchemaV1 = schema.object({ + id: schema.string(), + last_seen: schema.string(), +}); + +export type BackgroundTaskNode = TypeOf; diff --git a/x-pack/plugins/task_manager/tsconfig.json b/x-pack/plugins/task_manager/tsconfig.json index 2c265a93e55a1..5ae81e9097114 100644 --- a/x-pack/plugins/task_manager/tsconfig.json +++ b/x-pack/plugins/task_manager/tsconfig.json @@ -1,7 +1,7 @@ { "extends": "../../../tsconfig.base.json", "compilerOptions": { - "outDir": "target/types", + "outDir": "target/types" }, "include": [ "server/**/*", @@ -22,9 +22,10 @@ "@kbn/core-saved-objects-utils-server", "@kbn/core-test-helpers-kbn-server", "@kbn/core-saved-objects-server", - "@kbn/alerting-state-types" + "@kbn/alerting-state-types", + "@kbn/core-saved-objects-api-server", + "@kbn/logging", + "@kbn/core-lifecycle-server" ], - "exclude": [ - "target/**/*", - ] + "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/transform/server/types.ts b/x-pack/plugins/transform/server/types.ts index e5c44aafe163a..d0a388b756e79 100644 --- a/x-pack/plugins/transform/server/types.ts +++ b/x-pack/plugins/transform/server/types.ts @@ -8,7 +8,7 @@ import type { IRouter, CoreStart } from '@kbn/core/server'; import type { PluginStart as DataViewsServerPluginStart } from '@kbn/data-views-plugin/server'; import type { LicensingPluginSetup } from '@kbn/licensing-plugin/server'; -import type { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import type { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import type { AlertingPlugin } from '@kbn/alerting-plugin/server'; import type { FieldFormatsSetup, FieldFormatsStart } from '@kbn/field-formats-plugin/server'; import type { SecurityPluginSetup, SecurityPluginStart } from '@kbn/security-plugin/server'; diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 6ed8b8f82b952..43b0fdd793da6 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -1016,9 +1016,6 @@ "core.ui_settings.params.dateNanosFormatTitle": "Date au format nanosecondes", "core.ui_settings.params.dateNanosLinkTitle": "date_nanos", "core.ui_settings.params.dayOfWeekText.invalidValidationMessage": "Jour de la semaine non valide : {dayOfWeek}", - "core.ui_settings.params.defaultRoute.defaultRouteIsRelativeValidationMessage": "Doit être une URL relative.", - "core.ui_settings.params.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.", - "core.ui_settings.params.defaultRoute.defaultRouteTitle": "Chemin par défaut", "core.ui_settings.params.disableAnimationsText": "Désactivez toutes les animations non nécessaires dans l'interface utilisateur de Kibana. Actualisez la page pour appliquer les modifications.", "core.ui_settings.params.disableAnimationsTitle": "Désactiver les animations", "core.ui_settings.params.hideAnnouncements": "Masquer les annonces", @@ -6656,7 +6653,6 @@ "textBasedEditor.query.textBasedLanguagesEditor.runQuery": "Exécuter la requête", "textBasedEditor.query.textBasedLanguagesEditor.sourceCommands": "Commandes sources", "textBasedEditor.query.textBasedLanguagesEditor.submitFeedback": "Soumettre un commentaire", - "textBasedEditor.query.textBasedLanguagesEditor.timestampDetected": "@timestamp trouvé", "textBasedEditor.query.textBasedLanguagesEditor.timestampNotDetected": "@timestamp non trouvé", "textBasedEditor.query.textBasedLanguagesEditor.warningCount": "{count} {count, plural, one {avertissement} other {avertissements}}", "textBasedEditor.query.textBasedLanguagesEditor.warningsTitle": "Avertissements", @@ -37909,13 +37905,7 @@ "xpack.securitySolution.timeline.searchOrFilter.searchKqlPlaceholder": "Rechercher des événements", "xpack.securitySolution.timeline.searchOrFilter.searchKqlSelectedText": "Rechercher", "xpack.securitySolution.timeline.searchOrFilter.searchKqlTooltip": "Les événements des fournisseurs de données ci-dessus sont combinés avec les résultats de ce KQL", - "xpack.securitySolution.timeline.sidePanel.hostDetails.close": "fermer", - "xpack.securitySolution.timeline.sidePanel.hostDetails.hostDetailsPageLink": "Afficher la page de détails", - "xpack.securitySolution.timeline.sidePanel.hostDetails.title": "Détails de l'hôte", "xpack.securitySolution.timeline.sidePanel.maxAnomalyScoreByJobTitle": "Score maximal d'anomalie par tâche", - "xpack.securitySolution.timeline.sidePanel.networkDetails.close": "fermer", - "xpack.securitySolution.timeline.sidePanel.networkDetails.networkDetailsPageLink": "Afficher la page de détails", - "xpack.securitySolution.timeline.sidePanel.networkDetails.title": "Détails réseau", "xpack.securitySolution.timeline.sortAZLabel": "Trier A-Z", "xpack.securitySolution.timeline.sortFieldsButton": "Trier les champs", "xpack.securitySolution.timeline.sortZALabel": "Trier Z-A", @@ -42264,34 +42254,6 @@ "xpack.transform.type.unknown": "inconnu", "xpack.transform.wizard.nextStepButton": "Suivant", "xpack.transform.wizard.previousStepButton": "Précédent", - "xpack.triggersActionsUI.actionVariables.alertActionGroupLabel": "Groupe d'actions de l'alerte ayant programmé les actions pour la règle.", - "xpack.triggersActionsUI.actionVariables.alertActionGroupNameLabel": "Nom lisible par l'utilisateur du groupe d'actions de l'alerte ayant programmé les actions pour la règle.", - "xpack.triggersActionsUI.actionVariables.alertFlappingLabel": "Indicateur sur l'alerte spécifiant si le statut de l'alerte change fréquemment.", - "xpack.triggersActionsUI.actionVariables.alertIdLabel": "ID de l'alerte ayant programmé les actions pour la règle.", - "xpack.triggersActionsUI.actionVariables.allAlertsCountLabel": "Décompte de toutes les alertes.", - "xpack.triggersActionsUI.actionVariables.allAlertsDataLabel": "Tableau d'objets pour toutes les alertes.", - "xpack.triggersActionsUI.actionVariables.dateLabel": "Date à laquelle la règle a programmé l'action.", - "xpack.triggersActionsUI.actionVariables.kibanaBaseUrlLabel": "Valeur server.publicBaseUrl configurée ou chaîne vide si elle n'est pas configurée.", - "xpack.triggersActionsUI.actionVariables.legacyAlertActionGroupLabel": "Cet élément a été déclassé au profit de {variable}.", - "xpack.triggersActionsUI.actionVariables.legacyAlertActionGroupNameLabel": "Cet élément a été déclassé au profit de {variable}.", - "xpack.triggersActionsUI.actionVariables.legacyAlertInstanceIdLabel": "Cet élément a été déclassé au profit de {variable}.", - "xpack.triggersActionsUI.actionVariables.legacyAlertNameLabel": "Cet élément a été déclassé au profit de {variable}.", - "xpack.triggersActionsUI.actionVariables.legacyParamsLabel": "Cet élément a été déclassé au profit de {variable}.", - "xpack.triggersActionsUI.actionVariables.legacySpaceIdLabel": "Cet élément a été déclassé au profit de {variable}.", - "xpack.triggersActionsUI.actionVariables.legacyTagsLabel": "Cet élément a été déclassé au profit de {variable}.", - "xpack.triggersActionsUI.actionVariables.newAlertsCountLabel": "Décompte des nouvelles alertes.", - "xpack.triggersActionsUI.actionVariables.newAlertsDataLabel": "Tableau d'objets pour les nouvelles alertes.", - "xpack.triggersActionsUI.actionVariables.ongoingAlertsCountLabel": "Décompte des alertes en cours.", - "xpack.triggersActionsUI.actionVariables.ongoingAlertsDataLabel": "Tableau d'objets pour les alertes en cours.", - "xpack.triggersActionsUI.actionVariables.recoveredAlertsCountLabel": "Décompte des alertes récupérées.", - "xpack.triggersActionsUI.actionVariables.recoveredAlertsDataLabel": "Tableau d'objets pour les alertes récupérées.", - "xpack.triggersActionsUI.actionVariables.ruleIdLabel": "ID de la règle.", - "xpack.triggersActionsUI.actionVariables.ruleNameLabel": "Nom de la règle.", - "xpack.triggersActionsUI.actionVariables.ruleParamsLabel": "Paramètres de la règle.", - "xpack.triggersActionsUI.actionVariables.ruleSpaceIdLabel": "ID d'espace de la règle.", - "xpack.triggersActionsUI.actionVariables.ruleTagsLabel": "Balises de la règle.", - "xpack.triggersActionsUI.actionVariables.ruleTypeLabel": "Type de règle.", - "xpack.triggersActionsUI.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é.", "xpack.triggersActionsUI.alerts.breadcrumbTitle": "Alertes", "xpack.triggersActionsUI.alerts.table.actions.addToCase": "Ajouter à un cas existant", "xpack.triggersActionsUI.alerts.table.actions.addToNewCase": "Ajouter au nouveau cas", @@ -42620,9 +42582,6 @@ "xpack.triggersActionsUI.sections.actionTypeForm.accordion.deleteIconAriaLabel": "Supprimer", "xpack.triggersActionsUI.sections.actionTypeForm.ActionAlertsFilterQueryPlaceholder": "Filtrer les alertes à l'aide de la syntaxe KQL", "xpack.triggersActionsUI.sections.actionTypeForm.ActionAlertsFilterQueryToggleLabel": "Si l'alerte correspond à une requête", - "xpack.triggersActionsUI.sections.actionTypeForm.ActionAlertsFilterTimeframeTimezoneLabel": "Fuseau horaire", - "xpack.triggersActionsUI.sections.actionTypeForm.ActionAlertsFilterTimeframeToggleLabel": "Si l'alerte est générée pendant l'intervalle de temps", - "xpack.triggersActionsUI.sections.actionTypeForm.ActionAlertsFilterTimeframeWeekdays": "Jours de la semaine", "xpack.triggersActionsUI.sections.actionTypeForm.actionDisabledTitle": "Cette action est désactivée", "xpack.triggersActionsUI.sections.actionTypeForm.actionErrorToolTip": "L’action contient des erreurs.", "xpack.triggersActionsUI.sections.actionTypeForm.actionIdLabel": "Connecteur {connectorInstance}", @@ -42632,7 +42591,6 @@ "xpack.triggersActionsUI.sections.actionTypeForm.addNewConnectorEmptyButton": "Ajouter un connecteur", "xpack.triggersActionsUI.sections.actionTypeForm.error.requiredFilterQuery": "Une requête personnalisée est requise.", "xpack.triggersActionsUI.sections.actionTypeForm.existingAlertActionTypeEditTitle": "{actionConnectorName}", - "xpack.triggersActionsUI.sections.actionTypeForm.notifyWhenThrottleWarning": "Les intervalles d'action personnalisés ne peuvent pas être plus courts que l'intervalle de vérification de la règle", "xpack.triggersActionsUI.sections.actionTypeForm.runWhenGroupTitle": "Exécuter lorsque {groupName}", "xpack.triggersActionsUI.sections.actionTypeForm.summaryGroupTitle": "Résumé des alertes", "xpack.triggersActionsUI.sections.actionTypeForm.warning.publicBaseUrl": "server.publicBaseUrl n'est pas défini. Les URL générées seront relatives ou vides.", @@ -42844,10 +42802,6 @@ "xpack.triggersActionsUI.sections.ruleEdit.saveButtonLabel": "Enregistrer", "xpack.triggersActionsUI.sections.ruleEdit.saveErrorNotificationText": "Impossible de mettre à jour la règle.", "xpack.triggersActionsUI.sections.ruleEdit.saveSuccessNotificationText": "Mise à jour de \"{ruleName}\" effectuée", - "xpack.triggersActionsUI.sections.ruleForm.actionNotifyWhen.actionFrequencyLabel": "Fréquence d'action", - "xpack.triggersActionsUI.sections.ruleForm.actionNotifyWhen.forEachOption": "Pour chaque alerte", - "xpack.triggersActionsUI.sections.ruleForm.actionNotifyWhen.summaryOption": "Résumé des alertes", - "xpack.triggersActionsUI.sections.ruleForm.actionNotifyWhen.summaryOrRulePerSelectRoleDescription": "Sélection du type de fréquence d'action", "xpack.triggersActionsUI.sections.ruleForm.changeRuleTypeAriaLabel": "Supprimer", "xpack.triggersActionsUI.sections.ruleForm.checkEveryHelpSuggestionText": "Des intervalles inférieurs à {minimum} ne sont pas recommandés pour des raisons de performances.", "xpack.triggersActionsUI.sections.ruleForm.checkEveryHelpText": "L'intervalle doit être au minimum de {minimum}.", @@ -42866,7 +42820,6 @@ "xpack.triggersActionsUI.sections.ruleForm.error.requiredIntervalText": "L'intervalle de vérification est requis.", "xpack.triggersActionsUI.sections.ruleForm.error.requiredNameText": "Le nom est requis.", "xpack.triggersActionsUI.sections.ruleForm.error.requiredRuleTypeIdText": "Le type de règle est requis.", - "xpack.triggersActionsUI.sections.ruleForm.frequencyNotifyWhen.label": "Exécuter chaque", "xpack.triggersActionsUI.sections.ruleForm.loadingRuleTypeParamsDescription": "Chargement des paramètres de types de règles…", "xpack.triggersActionsUI.sections.ruleForm.loadingRuleTypesDescription": "Chargement des types de règles…", "xpack.triggersActionsUI.sections.ruleForm.renotifyFieldLabel": "Notifier", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 286856ab7cb9a..c3ae051fef551 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -1016,9 +1016,6 @@ "core.ui_settings.params.dateNanosFormatTitle": "ナノ秒フォーマットでの日付", "core.ui_settings.params.dateNanosLinkTitle": "date_nanos", "core.ui_settings.params.dayOfWeekText.invalidValidationMessage": "無効な曜日:{dayOfWeek}", - "core.ui_settings.params.defaultRoute.defaultRouteIsRelativeValidationMessage": "相対URLでなければなりません。", - "core.ui_settings.params.defaultRoute.defaultRouteText": "この設定は、Kibana起動時のデフォルトのルートを設定します。この設定で、Kibana起動時のランディングページを変更できます。ルートは相対URLでなければなりません。", - "core.ui_settings.params.defaultRoute.defaultRouteTitle": "デフォルトのルート", "core.ui_settings.params.disableAnimationsText": "Kibana UIの不要なアニメーションをオフにします。変更を適用するにはページを更新してください。", "core.ui_settings.params.disableAnimationsTitle": "アニメーションを無効にする", "core.ui_settings.params.hideAnnouncements": "お知らせを非表示", @@ -6632,7 +6629,7 @@ "textBasedEditor.query.textBasedLanguagesEditor.runQuery": "クエリを実行", "textBasedEditor.query.textBasedLanguagesEditor.sourceCommands": "ソースコマンド", "textBasedEditor.query.textBasedLanguagesEditor.submitFeedback": "フィードバックを送信", - "textBasedEditor.query.textBasedLanguagesEditor.timestampDetected": "@timestampが見つかりました", + "": "@timestampが見つかりました", "textBasedEditor.query.textBasedLanguagesEditor.timestampNotDetected": "@timestampが見つかりません", "textBasedEditor.query.textBasedLanguagesEditor.warningCount": "{count} {count, plural, other {件の警告}}", "textBasedEditor.query.textBasedLanguagesEditor.warningsTitle": "警告", @@ -37778,13 +37775,7 @@ "xpack.securitySolution.timeline.searchOrFilter.searchKqlPlaceholder": "イベントを検索", "xpack.securitySolution.timeline.searchOrFilter.searchKqlSelectedText": "検索", "xpack.securitySolution.timeline.searchOrFilter.searchKqlTooltip": "上のデータプロバイダーからのイベントは、この KQL からの結果と組み合わされます。", - "xpack.securitySolution.timeline.sidePanel.hostDetails.close": "閉じる", - "xpack.securitySolution.timeline.sidePanel.hostDetails.hostDetailsPageLink": "詳細ページを表示", - "xpack.securitySolution.timeline.sidePanel.hostDetails.title": "ホストの詳細", "xpack.securitySolution.timeline.sidePanel.maxAnomalyScoreByJobTitle": "ジョブ別の最高異常スコア", - "xpack.securitySolution.timeline.sidePanel.networkDetails.close": "閉じる", - "xpack.securitySolution.timeline.sidePanel.networkDetails.networkDetailsPageLink": "詳細ページを表示", - "xpack.securitySolution.timeline.sidePanel.networkDetails.title": "ネットワーク詳細", "xpack.securitySolution.timeline.sortAZLabel": "A-Zの昇順で並べ替え", "xpack.securitySolution.timeline.sortFieldsButton": "フィールドの並べ替え", "xpack.securitySolution.timeline.sortZALabel": "ZーAの降順で並べ替え", @@ -42126,34 +42117,6 @@ "xpack.transform.type.unknown": "不明", "xpack.transform.wizard.nextStepButton": "次へ", "xpack.transform.wizard.previousStepButton": "前へ", - "xpack.triggersActionsUI.actionVariables.alertActionGroupLabel": "ルールのアクションをスケジュールしたアラートのアクショングループ。", - "xpack.triggersActionsUI.actionVariables.alertActionGroupNameLabel": "ルールのアクションをスケジュールしたアラートのアクショングループの人間が読み取れる名前。", - "xpack.triggersActionsUI.actionVariables.alertFlappingLabel": "アラートの状態が繰り返し変化しているかどうかを示すアラートのフラグ。", - "xpack.triggersActionsUI.actionVariables.alertIdLabel": "ルールのアクションをスケジュールしたアラートのID。", - "xpack.triggersActionsUI.actionVariables.allAlertsCountLabel": "すべてのアラートのカウント。", - "xpack.triggersActionsUI.actionVariables.allAlertsDataLabel": "すべてのアラートのオブジェクトの配列。", - "xpack.triggersActionsUI.actionVariables.dateLabel": "ルールがアクションをスケジュールした日付。", - "xpack.triggersActionsUI.actionVariables.kibanaBaseUrlLabel": "構成したserver.publicBaseUrl値。構成していない場合は、空の文字列。", - "xpack.triggersActionsUI.actionVariables.legacyAlertActionGroupLabel": "{variable}の導入により、これは廃止される予定です。", - "xpack.triggersActionsUI.actionVariables.legacyAlertActionGroupNameLabel": "{variable}の導入により、これは廃止される予定です。", - "xpack.triggersActionsUI.actionVariables.legacyAlertInstanceIdLabel": "{variable}の導入により、これは廃止される予定です。", - "xpack.triggersActionsUI.actionVariables.legacyAlertNameLabel": "{variable}の導入により、これは廃止される予定です。", - "xpack.triggersActionsUI.actionVariables.legacyParamsLabel": "{variable}の導入により、これは廃止される予定です。", - "xpack.triggersActionsUI.actionVariables.legacySpaceIdLabel": "{variable}の導入により、これは廃止される予定です。", - "xpack.triggersActionsUI.actionVariables.legacyTagsLabel": "{variable}の導入により、これは廃止される予定です。", - "xpack.triggersActionsUI.actionVariables.newAlertsCountLabel": "新しいアラートのカウント。", - "xpack.triggersActionsUI.actionVariables.newAlertsDataLabel": "新しいアラートのオブジェクトの配列。", - "xpack.triggersActionsUI.actionVariables.ongoingAlertsCountLabel": "実行中のアラートのカウント。", - "xpack.triggersActionsUI.actionVariables.ongoingAlertsDataLabel": "実行中のアラートのオブジェクトの配列。", - "xpack.triggersActionsUI.actionVariables.recoveredAlertsCountLabel": "回復済みのアラートのカウント。", - "xpack.triggersActionsUI.actionVariables.recoveredAlertsDataLabel": "回復済みのアラートのオブジェクトの配列。", - "xpack.triggersActionsUI.actionVariables.ruleIdLabel": "ルールの ID。", - "xpack.triggersActionsUI.actionVariables.ruleNameLabel": "ルールの名前。", - "xpack.triggersActionsUI.actionVariables.ruleParamsLabel": "ルールのパラメーター。", - "xpack.triggersActionsUI.actionVariables.ruleSpaceIdLabel": "ルールのスペースID。", - "xpack.triggersActionsUI.actionVariables.ruleTagsLabel": "ルールのタグ。", - "xpack.triggersActionsUI.actionVariables.ruleTypeLabel": "ルールのタイプ。", - "xpack.triggersActionsUI.actionVariables.ruleUrlLabel": "アラートを生成したルールのURL。server.publicBaseUrlが構成されていない場合は、空の文字列になります。", "xpack.triggersActionsUI.alerts.breadcrumbTitle": "アラート", "xpack.triggersActionsUI.alerts.table.actions.addToCase": "既存のケースに追加", "xpack.triggersActionsUI.alerts.table.actions.addToNewCase": "新しいケースに追加", @@ -42481,9 +42444,6 @@ "xpack.triggersActionsUI.sections.actionTypeForm.accordion.deleteIconAriaLabel": "削除", "xpack.triggersActionsUI.sections.actionTypeForm.ActionAlertsFilterQueryPlaceholder": "KQL構文を使用してアラートをフィルター", "xpack.triggersActionsUI.sections.actionTypeForm.ActionAlertsFilterQueryToggleLabel": "アラートがクエリと一致する場合", - "xpack.triggersActionsUI.sections.actionTypeForm.ActionAlertsFilterTimeframeTimezoneLabel": "タイムゾーン", - "xpack.triggersActionsUI.sections.actionTypeForm.ActionAlertsFilterTimeframeToggleLabel": "アラートがタイムフレーム中に生成された場合", - "xpack.triggersActionsUI.sections.actionTypeForm.ActionAlertsFilterTimeframeWeekdays": "曜日", "xpack.triggersActionsUI.sections.actionTypeForm.actionDisabledTitle": "このアクションは無効です", "xpack.triggersActionsUI.sections.actionTypeForm.actionErrorToolTip": "アクションにはエラーがあります。", "xpack.triggersActionsUI.sections.actionTypeForm.actionIdLabel": "{connectorInstance}コネクター", @@ -42493,7 +42453,6 @@ "xpack.triggersActionsUI.sections.actionTypeForm.addNewConnectorEmptyButton": "コネクターの追加", "xpack.triggersActionsUI.sections.actionTypeForm.error.requiredFilterQuery": "カスタムクエリが必要です。", "xpack.triggersActionsUI.sections.actionTypeForm.existingAlertActionTypeEditTitle": "{actionConnectorName}", - "xpack.triggersActionsUI.sections.actionTypeForm.notifyWhenThrottleWarning": "カスタムアクション間隔をルールのチェック間隔よりも短くすることはできません", "xpack.triggersActionsUI.sections.actionTypeForm.runWhenGroupTitle": "{groupName}のときに実行", "xpack.triggersActionsUI.sections.actionTypeForm.summaryGroupTitle": "アラートの概要", "xpack.triggersActionsUI.sections.actionTypeForm.warning.publicBaseUrl": "server.publicBaseUrlが設定されていません。生成されたURLは相対URLか空になります。", @@ -42704,10 +42663,6 @@ "xpack.triggersActionsUI.sections.ruleEdit.operationName": "編集", "xpack.triggersActionsUI.sections.ruleEdit.saveButtonLabel": "保存", "xpack.triggersActionsUI.sections.ruleEdit.saveErrorNotificationText": "ルールを更新できません", - "xpack.triggersActionsUI.sections.ruleForm.actionNotifyWhen.actionFrequencyLabel": "アクション頻度", - "xpack.triggersActionsUI.sections.ruleForm.actionNotifyWhen.forEachOption": "各アラート", - "xpack.triggersActionsUI.sections.ruleForm.actionNotifyWhen.summaryOption": "アラートの概要", - "xpack.triggersActionsUI.sections.ruleForm.actionNotifyWhen.summaryOrRulePerSelectRoleDescription": "アクション頻度タイプ選択", "xpack.triggersActionsUI.sections.ruleForm.changeRuleTypeAriaLabel": "削除", "xpack.triggersActionsUI.sections.ruleForm.checkEveryHelpSuggestionText": "パフォーマンスの考慮から、{minimum}未満の間隔は推奨されません。", "xpack.triggersActionsUI.sections.ruleForm.checkEveryHelpText": "間隔は{minimum}以上でなければなりません。", @@ -42726,7 +42681,6 @@ "xpack.triggersActionsUI.sections.ruleForm.error.requiredIntervalText": "確認間隔が必要です。", "xpack.triggersActionsUI.sections.ruleForm.error.requiredNameText": "名前が必要です。", "xpack.triggersActionsUI.sections.ruleForm.error.requiredRuleTypeIdText": "ルールタイプは必須です。", - "xpack.triggersActionsUI.sections.ruleForm.frequencyNotifyWhen.label": "次の間隔で実行", "xpack.triggersActionsUI.sections.ruleForm.loadingRuleTypeParamsDescription": "ルールタイプパラメーターを読み込んでいます…", "xpack.triggersActionsUI.sections.ruleForm.loadingRuleTypesDescription": "ルールタイプを読み込んでいます…", "xpack.triggersActionsUI.sections.ruleForm.renotifyFieldLabel": "通知", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 115505b917905..f96a1de934d35 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -1018,9 +1018,6 @@ "core.ui_settings.params.dateNanosFormatTitle": "纳秒格式的日期", "core.ui_settings.params.dateNanosLinkTitle": "date_nanos", "core.ui_settings.params.dayOfWeekText.invalidValidationMessage": "周内日无效:{dayOfWeek}", - "core.ui_settings.params.defaultRoute.defaultRouteIsRelativeValidationMessage": "必须是相对 URL。", - "core.ui_settings.params.defaultRoute.defaultRouteText": "此设置用于指定打开 Kibana 时的默认路由。您可以使用此设置修改打开 Kibana 时的登陆页面。路由必须是相对 URL。", - "core.ui_settings.params.defaultRoute.defaultRouteTitle": "默认路由", "core.ui_settings.params.disableAnimationsText": "在 Kibana UI 中关闭所有不必要的动画。刷新页面可应用所做的更改。", "core.ui_settings.params.disableAnimationsTitle": "禁用动画", "core.ui_settings.params.hideAnnouncements": "隐藏公告", @@ -6665,7 +6662,6 @@ "textBasedEditor.query.textBasedLanguagesEditor.runQuery": "运行查询", "textBasedEditor.query.textBasedLanguagesEditor.sourceCommands": "源命令", "textBasedEditor.query.textBasedLanguagesEditor.submitFeedback": "提交反馈", - "textBasedEditor.query.textBasedLanguagesEditor.timestampDetected": "找到 @timestamp", "textBasedEditor.query.textBasedLanguagesEditor.timestampNotDetected": "未找到 @timestamp", "textBasedEditor.query.textBasedLanguagesEditor.warningCount": "{count} 个{count, plural, other {警告}}", "textBasedEditor.query.textBasedLanguagesEditor.warningsTitle": "警告", @@ -37948,13 +37944,7 @@ "xpack.securitySolution.timeline.searchOrFilter.searchKqlPlaceholder": "搜索事件", "xpack.securitySolution.timeline.searchOrFilter.searchKqlSelectedText": "搜索", "xpack.securitySolution.timeline.searchOrFilter.searchKqlTooltip": "来自上述数据提供程序的事件与此 KQL 的结果进行组合", - "xpack.securitySolution.timeline.sidePanel.hostDetails.close": "关闭", - "xpack.securitySolution.timeline.sidePanel.hostDetails.hostDetailsPageLink": "查看详情页面", - "xpack.securitySolution.timeline.sidePanel.hostDetails.title": "主机详情", "xpack.securitySolution.timeline.sidePanel.maxAnomalyScoreByJobTitle": "最大异常分数(按作业)", - "xpack.securitySolution.timeline.sidePanel.networkDetails.close": "关闭", - "xpack.securitySolution.timeline.sidePanel.networkDetails.networkDetailsPageLink": "查看详情页面", - "xpack.securitySolution.timeline.sidePanel.networkDetails.title": "网络详情", "xpack.securitySolution.timeline.sortAZLabel": "A-Z 排序", "xpack.securitySolution.timeline.sortFieldsButton": "排序字段", "xpack.securitySolution.timeline.sortZALabel": "Z-A 排序", @@ -42314,34 +42304,6 @@ "xpack.transform.type.unknown": "未知", "xpack.transform.wizard.nextStepButton": "下一步", "xpack.transform.wizard.previousStepButton": "上一步", - "xpack.triggersActionsUI.actionVariables.alertActionGroupLabel": "已为规则计划操作的告警的操作组。", - "xpack.triggersActionsUI.actionVariables.alertActionGroupNameLabel": "已为规则计划操作的告警的操作组的可人工读取名称。", - "xpack.triggersActionsUI.actionVariables.alertFlappingLabel": "告警上指示告警状态是否重复更改的标志。", - "xpack.triggersActionsUI.actionVariables.alertIdLabel": "已为规则计划操作的告警的 ID。", - "xpack.triggersActionsUI.actionVariables.allAlertsCountLabel": "所有告警的计数。", - "xpack.triggersActionsUI.actionVariables.allAlertsDataLabel": "所有告警的对象数组。", - "xpack.triggersActionsUI.actionVariables.dateLabel": "规则计划操作的日期。", - "xpack.triggersActionsUI.actionVariables.kibanaBaseUrlLabel": "配置的 server.publicBaseUrl 值,如果未配置,则为空字符串。", - "xpack.triggersActionsUI.actionVariables.legacyAlertActionGroupLabel": "其已弃用,将由 {variable} 替代。", - "xpack.triggersActionsUI.actionVariables.legacyAlertActionGroupNameLabel": "其已弃用,将由 {variable} 替代。", - "xpack.triggersActionsUI.actionVariables.legacyAlertInstanceIdLabel": "其已弃用,将由 {variable} 替代。", - "xpack.triggersActionsUI.actionVariables.legacyAlertNameLabel": "其已弃用,将由 {variable} 替代。", - "xpack.triggersActionsUI.actionVariables.legacyParamsLabel": "其已弃用,将由 {variable} 替代。", - "xpack.triggersActionsUI.actionVariables.legacySpaceIdLabel": "其已弃用,将由 {variable} 替代。", - "xpack.triggersActionsUI.actionVariables.legacyTagsLabel": "其已弃用,将由 {variable} 替代。", - "xpack.triggersActionsUI.actionVariables.newAlertsCountLabel": "新告警的计数。", - "xpack.triggersActionsUI.actionVariables.newAlertsDataLabel": "新告警的对象数组。", - "xpack.triggersActionsUI.actionVariables.ongoingAlertsCountLabel": "进行中的告警的计数。", - "xpack.triggersActionsUI.actionVariables.ongoingAlertsDataLabel": "进行中的告警的对象数组。", - "xpack.triggersActionsUI.actionVariables.recoveredAlertsCountLabel": "已恢复告警的计数。", - "xpack.triggersActionsUI.actionVariables.recoveredAlertsDataLabel": "已恢复告警的对象数组。", - "xpack.triggersActionsUI.actionVariables.ruleIdLabel": "规则的 ID。", - "xpack.triggersActionsUI.actionVariables.ruleNameLabel": "规则的名称。", - "xpack.triggersActionsUI.actionVariables.ruleParamsLabel": "规则的参数。", - "xpack.triggersActionsUI.actionVariables.ruleSpaceIdLabel": "规则的工作区 ID。", - "xpack.triggersActionsUI.actionVariables.ruleTagsLabel": "规则的标签。", - "xpack.triggersActionsUI.actionVariables.ruleTypeLabel": "规则的类型。", - "xpack.triggersActionsUI.actionVariables.ruleUrlLabel": "生成告警的规则的 URL。如果未配置 server.publicBaseUrl,这将为空字符串。", "xpack.triggersActionsUI.alerts.breadcrumbTitle": "告警", "xpack.triggersActionsUI.alerts.table.actions.addToCase": "添加到现有案例", "xpack.triggersActionsUI.alerts.table.actions.addToNewCase": "添加到新案例", @@ -42669,9 +42631,6 @@ "xpack.triggersActionsUI.sections.actionTypeForm.accordion.deleteIconAriaLabel": "删除", "xpack.triggersActionsUI.sections.actionTypeForm.ActionAlertsFilterQueryPlaceholder": "使用 KQL 语法筛选告警", "xpack.triggersActionsUI.sections.actionTypeForm.ActionAlertsFilterQueryToggleLabel": "如果告警与查询匹配", - "xpack.triggersActionsUI.sections.actionTypeForm.ActionAlertsFilterTimeframeTimezoneLabel": "时区", - "xpack.triggersActionsUI.sections.actionTypeForm.ActionAlertsFilterTimeframeToggleLabel": "如果在时间范围内生成了告警", - "xpack.triggersActionsUI.sections.actionTypeForm.ActionAlertsFilterTimeframeWeekdays": "星期几", "xpack.triggersActionsUI.sections.actionTypeForm.actionDisabledTitle": "此操作已禁用", "xpack.triggersActionsUI.sections.actionTypeForm.actionErrorToolTip": "操作包含错误。", "xpack.triggersActionsUI.sections.actionTypeForm.actionIdLabel": "{connectorInstance} 连接器", @@ -42681,7 +42640,6 @@ "xpack.triggersActionsUI.sections.actionTypeForm.addNewConnectorEmptyButton": "添加连接器", "xpack.triggersActionsUI.sections.actionTypeForm.error.requiredFilterQuery": "需要定制查询。", "xpack.triggersActionsUI.sections.actionTypeForm.existingAlertActionTypeEditTitle": "{actionConnectorName}", - "xpack.triggersActionsUI.sections.actionTypeForm.notifyWhenThrottleWarning": "定制操作时间间隔不能短于规则的检查时间间隔", "xpack.triggersActionsUI.sections.actionTypeForm.runWhenGroupTitle": "当 {groupName} 时运行", "xpack.triggersActionsUI.sections.actionTypeForm.summaryGroupTitle": "告警的摘要", "xpack.triggersActionsUI.sections.actionTypeForm.warning.publicBaseUrl": "未设置 server.publicBaseUrl。生成的 URL 将为相对 URL 或为空。", @@ -42893,10 +42851,6 @@ "xpack.triggersActionsUI.sections.ruleEdit.saveButtonLabel": "保存", "xpack.triggersActionsUI.sections.ruleEdit.saveErrorNotificationText": "无法更新规则。", "xpack.triggersActionsUI.sections.ruleEdit.saveSuccessNotificationText": "已更新“{ruleName}”", - "xpack.triggersActionsUI.sections.ruleForm.actionNotifyWhen.actionFrequencyLabel": "操作频率", - "xpack.triggersActionsUI.sections.ruleForm.actionNotifyWhen.forEachOption": "对于每个告警", - "xpack.triggersActionsUI.sections.ruleForm.actionNotifyWhen.summaryOption": "告警的摘要", - "xpack.triggersActionsUI.sections.ruleForm.actionNotifyWhen.summaryOrRulePerSelectRoleDescription": "操作频率类型选择", "xpack.triggersActionsUI.sections.ruleForm.changeRuleTypeAriaLabel": "删除", "xpack.triggersActionsUI.sections.ruleForm.checkEveryHelpSuggestionText": "出于性能考虑,不建议时间间隔小于 {minimum}。", "xpack.triggersActionsUI.sections.ruleForm.checkEveryHelpText": "时间间隔必须至少为 {minimum}。", @@ -42915,7 +42869,6 @@ "xpack.triggersActionsUI.sections.ruleForm.error.requiredIntervalText": "“检查时间间隔”必填。", "xpack.triggersActionsUI.sections.ruleForm.error.requiredNameText": "“名称”必填。", "xpack.triggersActionsUI.sections.ruleForm.error.requiredRuleTypeIdText": "“规则类型”必填。", - "xpack.triggersActionsUI.sections.ruleForm.frequencyNotifyWhen.label": "运行间隔", "xpack.triggersActionsUI.sections.ruleForm.loadingRuleTypeParamsDescription": "正在加载规则类型参数……", "xpack.triggersActionsUI.sections.ruleForm.loadingRuleTypesDescription": "正在加载规则类型……", "xpack.triggersActionsUI.sections.ruleForm.renotifyFieldLabel": "通知", diff --git a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_rule_aad_fields.ts b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_rule_aad_fields.ts index 1ad7106910113..91aaf19776d8b 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_rule_aad_fields.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_rule_aad_fields.ts @@ -7,30 +7,14 @@ import { DataViewField } from '@kbn/data-views-plugin/common'; import { useKibana } from '@kbn/kibana-react-plugin/public'; -import { BASE_RAC_ALERTS_API_PATH } from '@kbn/rule-registry-plugin/common'; -import { HttpSetup } from '@kbn/core/public'; import { useQuery } from '@tanstack/react-query'; import { i18n } from '@kbn/i18n'; import { useMemo } from 'react'; +import { fetchRuleTypeAadTemplateFields } from '@kbn/alerts-ui-shared/src/common/apis/fetch_rule_type_aad_template_fields'; import { TriggersAndActionsUiServices } from '../..'; const EMPTY_AAD_FIELDS: DataViewField[] = []; -async function fetchAadFields({ - http, - ruleTypeId, -}: { - http: HttpSetup; - ruleTypeId?: string; -}): Promise { - if (!ruleTypeId) return EMPTY_AAD_FIELDS; - const fields = await http.get(`${BASE_RAC_ALERTS_API_PATH}/aad_fields`, { - query: { ruleTypeId }, - }); - - return fields; -} - export function useRuleAADFields(ruleTypeId?: string): { aadFields: DataViewField[]; loading: boolean; @@ -41,7 +25,7 @@ export function useRuleAADFields(ruleTypeId?: string): { } = useKibana().services; const queryAadFieldsFn = () => { - return fetchAadFields({ http, ruleTypeId }); + return fetchRuleTypeAadTemplateFields({ http, ruleTypeId }); }; const onErrorFn = () => { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_rule_aad_template_fields.ts b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_rule_aad_template_fields.ts index 4152973d574be..d11fa4017d9d5 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_rule_aad_template_fields.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_rule_aad_template_fields.ts @@ -7,35 +7,14 @@ import type { HttpStart } from '@kbn/core-http-browser'; import { DataViewField } from '@kbn/data-views-plugin/common'; -import { BASE_RAC_ALERTS_API_PATH } from '@kbn/rule-registry-plugin/common'; import { ActionVariable } from '@kbn/alerting-plugin/common'; import { useEffect, useMemo, useState } from 'react'; import { EcsFlat } from '@elastic/ecs'; -import { EcsMetadata } from '@kbn/alerts-as-data-utils/src/field_maps/types'; -import { isEmpty } from 'lodash'; -export const getDescription = (fieldName: string, ecsFlat: Record) => { - let ecsField = ecsFlat[fieldName]; - if (isEmpty(ecsField?.description ?? '') && fieldName.includes('kibana.alert.')) { - ecsField = ecsFlat[fieldName.replace('kibana.alert.', '')]; - } - return ecsField?.description ?? ''; -}; - -async function loadRuleTypeAadTemplateFields({ - http, - ruleTypeId, -}: { - http: HttpStart; - ruleTypeId: string; -}): Promise { - if (!ruleTypeId || !http) return []; - const fields = await http.get(`${BASE_RAC_ALERTS_API_PATH}/aad_fields`, { - query: { ruleTypeId }, - }); - - return fields; -} +import { + fetchRuleTypeAadTemplateFields, + getDescription, +} from '@kbn/alerts-ui-shared/src/common/apis/fetch_rule_type_aad_template_fields'; export function useRuleTypeAadTemplateFields( http: HttpStart, @@ -49,7 +28,7 @@ export function useRuleTypeAadTemplateFields( useEffect(() => { if (enabled && data.length === 0 && ruleTypeId) { setIsLoading(true); - loadRuleTypeAadTemplateFields({ http, ruleTypeId }).then((res) => { + fetchRuleTypeAadTemplateFields({ http, ruleTypeId }).then((res) => { setData(res); setIsLoading(false); }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/action_connector_api/connector_types.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/action_connector_api/connector_types.ts index 8ec463113b6a0..eacf0db50f452 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/action_connector_api/connector_types.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/action_connector_api/connector_types.ts @@ -4,55 +4,5 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { HttpSetup } from '@kbn/core/public'; -import { - AsApiContract, - INTERNAL_BASE_ACTION_API_PATH, - RewriteRequestCase, -} from '@kbn/actions-plugin/common'; -import { BASE_ACTION_API_PATH } from '../../constants'; -import type { ActionType } from '../../../types'; - -const rewriteResponseRes = (results: Array>): ActionType[] => { - return results.map((item) => rewriteBodyReq(item)); -}; - -const rewriteBodyReq: RewriteRequestCase = ({ - enabled_in_config: enabledInConfig, - enabled_in_license: enabledInLicense, - minimum_license_required: minimumLicenseRequired, - supported_feature_ids: supportedFeatureIds, - is_system_action_type: isSystemActionType, - ...res -}: AsApiContract) => ({ - enabledInConfig, - enabledInLicense, - minimumLicenseRequired, - supportedFeatureIds, - isSystemActionType, - ...res, -}); - -export async function loadActionTypes({ - http, - featureId, - includeSystemActions = false, -}: { - http: HttpSetup; - featureId?: string; - includeSystemActions?: boolean; -}): Promise { - const path = includeSystemActions - ? `${INTERNAL_BASE_ACTION_API_PATH}/connector_types` - : `${BASE_ACTION_API_PATH}/connector_types`; - - const res = featureId - ? await http.get[0]>(path, { - query: { - feature_id: featureId, - }, - }) - : await http.get[0]>(path, {}); - return rewriteResponseRes(res); -} +export { fetchConnectorTypes as loadActionTypes } from '@kbn/alerts-ui-shared/src/common/apis/fetch_connector_types'; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/action_connector_api/connectors.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/action_connector_api/connectors.ts index 3e5fea634b479..9c06c015dc7cc 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/action_connector_api/connectors.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/action_connector_api/connectors.ts @@ -4,58 +4,5 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { HttpSetup } from '@kbn/core/public'; -import { - AsApiContract, - BASE_ACTION_API_PATH, - INTERNAL_BASE_ACTION_API_PATH, - RewriteRequestCase, -} from '@kbn/actions-plugin/common'; -import type { ActionConnector, ActionConnectorProps } from '../../../types'; -const rewriteResponseRes = ( - results: Array< - AsApiContract, Record>> - > -): Array, Record>> => { - return results.map((item) => transformConnector(item)); -}; - -const transformConnector: RewriteRequestCase< - ActionConnectorProps, Record> -> = ({ - connector_type_id: actionTypeId, - is_preconfigured: isPreconfigured, - is_deprecated: isDeprecated, - referenced_by_count: referencedByCount, - is_missing_secrets: isMissingSecrets, - is_system_action: isSystemAction, - ...res -}) => ({ - actionTypeId, - isPreconfigured, - isDeprecated, - referencedByCount, - isMissingSecrets, - isSystemAction, - ...res, -}); - -export async function loadAllActions({ - http, - includeSystemActions = false, -}: { - http: HttpSetup; - includeSystemActions?: boolean; -}): Promise { - // Use the internal get_all_system route to load all action connectors and preconfigured system action connectors - // This is necessary to load UI elements that require system action connectors, even if they're not selectable and - // editable from the connector selection UI like a normal action connector. - const path = includeSystemActions - ? `${INTERNAL_BASE_ACTION_API_PATH}/connectors` - : `${BASE_ACTION_API_PATH}/connectors`; - - const res = await http.get[0]>(path); - - return rewriteResponseRes(res) as ActionConnector[]; -} +export { fetchConnectors as loadAllActions } from '@kbn/alerts-ui-shared/src/common/apis/fetch_connectors'; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/action_variables.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/action_variables.ts deleted file mode 100644 index 38194c28195db..0000000000000 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/action_variables.ts +++ /dev/null @@ -1,355 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; -import { pick } from 'lodash'; -import { ActionVariable } from '@kbn/alerting-plugin/common'; -import { - ActionContextVariablesFlatten, - SummaryActionContextVariablesFlatten, -} from '@kbn/alerting-types'; -import { ActionVariables, REQUIRED_ACTION_VARIABLES, CONTEXT_ACTION_VARIABLES } from '../../types'; - -export type OmitMessageVariablesType = 'all' | 'keepContext'; - -function transformProvidedActionVariables( - actionVariables?: ActionVariables, - omitMessageVariables?: OmitMessageVariablesType -): ActionVariable[] { - if (!actionVariables) { - return []; - } - - const filteredActionVariables: ActionVariables = omitMessageVariables - ? omitMessageVariables === 'all' - ? pick(actionVariables, REQUIRED_ACTION_VARIABLES) - : pick(actionVariables, [...REQUIRED_ACTION_VARIABLES, ...CONTEXT_ACTION_VARIABLES]) - : actionVariables; - - const paramsVars = prefixKeys(filteredActionVariables.params, 'rule.params.'); - const contextVars = filteredActionVariables.context - ? prefixKeys(filteredActionVariables.context, 'context.') - : []; - const stateVars = filteredActionVariables.state - ? prefixKeys(filteredActionVariables.state, 'state.') - : []; - - return contextVars.concat(paramsVars, stateVars); -} - -// return a "flattened" list of action variables for an alertType -export function transformActionVariables( - actionVariables: ActionVariables, - summaryActionVariables?: ActionVariables, - omitMessageVariables?: OmitMessageVariablesType, - isSummaryAction?: boolean -): ActionVariable[] { - if (isSummaryAction) { - const alwaysProvidedVars = getSummaryAlertActionVariables(); - const transformedActionVars = transformProvidedActionVariables( - summaryActionVariables, - omitMessageVariables - ); - return alwaysProvidedVars.concat(transformedActionVars); - } - - const alwaysProvidedVars = getAlwaysProvidedActionVariables(); - const transformedActionVars = transformProvidedActionVariables( - actionVariables, - omitMessageVariables - ); - return alwaysProvidedVars.concat(transformedActionVars); -} - -export enum AlertProvidedActionVariables { - ruleId = 'rule.id', - ruleName = 'rule.name', - ruleSpaceId = 'rule.spaceId', - ruleTags = 'rule.tags', - ruleType = 'rule.type', - ruleUrl = 'rule.url', - ruleParams = 'rule.params', - date = 'date', - alertId = 'alert.id', - alertUuid = 'alert.uuid', - alertActionGroup = 'alert.actionGroup', - alertActionGroupName = 'alert.actionGroupName', - alertActionSubgroup = 'alert.actionSubgroup', - alertFlapping = 'alert.flapping', - kibanaBaseUrl = 'kibanaBaseUrl', - alertConsecutiveMatches = 'alert.consecutiveMatches', -} - -export enum LegacyAlertProvidedActionVariables { - alertId = 'alertId', - alertName = 'alertName', - alertInstanceId = 'alertInstanceId', - alertActionGroup = 'alertActionGroup', - alertActionGroupName = 'alertActionGroupName', - alertActionSubgroup = 'alertActionSubgroup', - tags = 'tags', - spaceId = 'spaceId', - params = 'params', -} - -export enum SummaryAlertProvidedActionVariables { - newAlertsCount = 'alerts.new.count', - newAlertsData = 'alerts.new.data', - ongoingAlertsCount = 'alerts.ongoing.count', - ongoingAlertsData = 'alerts.ongoing.data', - recoveredAlertsCount = 'alerts.recovered.count', - recoveredAlertsData = 'alerts.recovered.data', - allAlertsCount = 'alerts.all.count', - allAlertsData = 'alerts.all.data', -} - -type ActionVariablesWithoutName = Omit; - -const AlertProvidedActionVariableDescriptions: Record< - ActionContextVariablesFlatten, - ActionVariablesWithoutName -> = Object.freeze({ - [LegacyAlertProvidedActionVariables.alertId]: { - description: i18n.translate('xpack.triggersActionsUI.actionVariables.legacyAlertIdLabel', { - defaultMessage: 'This has been deprecated in favor of {variable}.', - values: { - variable: AlertProvidedActionVariables.ruleId, - }, - }), - deprecated: true, - }, - [LegacyAlertProvidedActionVariables.alertName]: { - deprecated: true, - description: i18n.translate('xpack.triggersActionsUI.actionVariables.legacyAlertNameLabel', { - defaultMessage: 'This has been deprecated in favor of {variable}.', - values: { - variable: AlertProvidedActionVariables.ruleName, - }, - }), - }, - [LegacyAlertProvidedActionVariables.alertInstanceId]: { - deprecated: true, - description: i18n.translate( - 'xpack.triggersActionsUI.actionVariables.legacyAlertInstanceIdLabel', - { - defaultMessage: 'This has been deprecated in favor of {variable}.', - values: { - variable: AlertProvidedActionVariables.alertId, - }, - } - ), - }, - [LegacyAlertProvidedActionVariables.alertActionGroup]: { - deprecated: true, - description: i18n.translate( - 'xpack.triggersActionsUI.actionVariables.legacyAlertActionGroupLabel', - { - defaultMessage: 'This has been deprecated in favor of {variable}.', - values: { - variable: AlertProvidedActionVariables.alertActionGroup, - }, - } - ), - }, - [LegacyAlertProvidedActionVariables.alertActionGroupName]: { - deprecated: true, - description: i18n.translate( - 'xpack.triggersActionsUI.actionVariables.legacyAlertActionGroupNameLabel', - { - defaultMessage: 'This has been deprecated in favor of {variable}.', - values: { - variable: AlertProvidedActionVariables.alertActionGroupName, - }, - } - ), - }, - [LegacyAlertProvidedActionVariables.tags]: { - deprecated: true, - description: i18n.translate('xpack.triggersActionsUI.actionVariables.legacyTagsLabel', { - defaultMessage: 'This has been deprecated in favor of {variable}.', - values: { - variable: AlertProvidedActionVariables.ruleTags, - }, - }), - }, - [LegacyAlertProvidedActionVariables.spaceId]: { - deprecated: true, - description: i18n.translate('xpack.triggersActionsUI.actionVariables.legacySpaceIdLabel', { - defaultMessage: 'This has been deprecated in favor of {variable}.', - values: { - variable: AlertProvidedActionVariables.ruleSpaceId, - }, - }), - }, - [LegacyAlertProvidedActionVariables.params]: { - deprecated: true, - description: i18n.translate('xpack.triggersActionsUI.actionVariables.legacyParamsLabel', { - defaultMessage: 'This has been deprecated in favor of {variable}.', - values: { - variable: AlertProvidedActionVariables.ruleParams, - }, - }), - }, - [AlertProvidedActionVariables.date]: { - description: i18n.translate('xpack.triggersActionsUI.actionVariables.dateLabel', { - defaultMessage: 'The date the rule scheduled the action.', - }), - }, - [AlertProvidedActionVariables.kibanaBaseUrl]: { - description: i18n.translate('xpack.triggersActionsUI.actionVariables.kibanaBaseUrlLabel', { - defaultMessage: - 'The configured server.publicBaseUrl value or empty string if not configured.', - }), - }, - [AlertProvidedActionVariables.ruleId]: { - description: i18n.translate('xpack.triggersActionsUI.actionVariables.ruleIdLabel', { - defaultMessage: 'The ID of the rule.', - }), - }, - [AlertProvidedActionVariables.ruleName]: { - description: i18n.translate('xpack.triggersActionsUI.actionVariables.ruleNameLabel', { - defaultMessage: 'The name of the rule.', - }), - }, - [AlertProvidedActionVariables.ruleSpaceId]: { - description: i18n.translate('xpack.triggersActionsUI.actionVariables.ruleSpaceIdLabel', { - defaultMessage: 'The space ID of the rule.', - }), - }, - [AlertProvidedActionVariables.ruleType]: { - description: i18n.translate('xpack.triggersActionsUI.actionVariables.ruleTypeLabel', { - defaultMessage: 'The type of rule.', - }), - }, - [AlertProvidedActionVariables.ruleTags]: { - description: i18n.translate('xpack.triggersActionsUI.actionVariables.ruleTagsLabel', { - defaultMessage: 'The tags of the rule.', - }), - }, - [AlertProvidedActionVariables.ruleParams]: { - description: i18n.translate('xpack.triggersActionsUI.actionVariables.ruleParamsLabel', { - defaultMessage: 'The parameters of the rule.', - }), - }, - [AlertProvidedActionVariables.ruleUrl]: { - description: i18n.translate('xpack.triggersActionsUI.actionVariables.ruleUrlLabel', { - defaultMessage: - 'The URL to the rule that generated the alert. This will be an empty string if the server.publicBaseUrl is not configured.', - }), - usesPublicBaseUrl: true, - }, - [AlertProvidedActionVariables.alertId]: { - description: i18n.translate('xpack.triggersActionsUI.actionVariables.alertIdLabel', { - defaultMessage: 'The ID of the alert that scheduled actions for the rule.', - }), - }, - [AlertProvidedActionVariables.alertUuid]: { - description: i18n.translate('xpack.triggersActionsUI.actionVariables.alertUuidLabel', { - defaultMessage: 'The UUID of the alert that scheduled actions for the rule.', - }), - }, - [AlertProvidedActionVariables.alertActionGroup]: { - description: i18n.translate('xpack.triggersActionsUI.actionVariables.alertActionGroupLabel', { - defaultMessage: 'The action group of the alert that scheduled actions for the rule.', - }), - }, - [AlertProvidedActionVariables.alertActionGroupName]: { - description: i18n.translate( - 'xpack.triggersActionsUI.actionVariables.alertActionGroupNameLabel', - { - defaultMessage: - 'The human readable name of the action group of the alert that scheduled actions for the rule.', - } - ), - }, - [AlertProvidedActionVariables.alertFlapping]: { - description: i18n.translate('xpack.triggersActionsUI.actionVariables.alertFlappingLabel', { - defaultMessage: - 'A flag on the alert that indicates whether the alert status is changing repeatedly.', - }), - }, - [AlertProvidedActionVariables.alertConsecutiveMatches]: { - description: i18n.translate( - 'xpack.triggersActionsUI.actionVariables.alertConsecutiveMatchesLabel', - { - defaultMessage: 'The number of consecutive runs that meet the rule conditions.', - } - ), - }, -}); - -const SummarizedAlertProvidedActionVariableDescriptions: Record< - SummaryActionContextVariablesFlatten, - Omit -> = Object.freeze({ - ...AlertProvidedActionVariableDescriptions, - [SummaryAlertProvidedActionVariables.allAlertsCount]: { - description: i18n.translate('xpack.triggersActionsUI.actionVariables.allAlertsCountLabel', { - defaultMessage: 'The count of all alerts.', - }), - }, - [SummaryAlertProvidedActionVariables.allAlertsData]: { - description: i18n.translate('xpack.triggersActionsUI.actionVariables.allAlertsDataLabel', { - defaultMessage: 'An array of objects for all alerts.', - }), - }, - [SummaryAlertProvidedActionVariables.newAlertsCount]: { - description: i18n.translate('xpack.triggersActionsUI.actionVariables.newAlertsCountLabel', { - defaultMessage: 'The count of new alerts.', - }), - }, - [SummaryAlertProvidedActionVariables.newAlertsData]: { - description: i18n.translate('xpack.triggersActionsUI.actionVariables.newAlertsDataLabel', { - defaultMessage: 'An array of objects for new alerts.', - }), - }, - [SummaryAlertProvidedActionVariables.ongoingAlertsCount]: { - description: i18n.translate('xpack.triggersActionsUI.actionVariables.ongoingAlertsCountLabel', { - defaultMessage: 'The count of ongoing alerts.', - }), - }, - [SummaryAlertProvidedActionVariables.ongoingAlertsData]: { - description: i18n.translate('xpack.triggersActionsUI.actionVariables.ongoingAlertsDataLabel', { - defaultMessage: 'An array of objects for ongoing alerts.', - }), - }, - [SummaryAlertProvidedActionVariables.recoveredAlertsCount]: { - description: i18n.translate( - 'xpack.triggersActionsUI.actionVariables.recoveredAlertsCountLabel', - { - defaultMessage: 'The count of recovered alerts.', - } - ), - }, - [SummaryAlertProvidedActionVariables.recoveredAlertsData]: { - description: i18n.translate( - 'xpack.triggersActionsUI.actionVariables.recoveredAlertsDataLabel', - { - defaultMessage: 'An array of objects for recovered alerts.', - } - ), - }, -}); - -function prefixKeys(actionVariables: ActionVariable[], prefix: string): ActionVariable[] { - return actionVariables.map((actionVariable) => { - return { ...actionVariable, name: `${prefix}${actionVariable.name}` }; - }); -} - -const transformContextVariables = ( - variables: Record -): ActionVariable[] => - Object.entries(variables).map(([key, variable]) => ({ ...variable, name: key })); - -export const getAlwaysProvidedActionVariables = (): ActionVariable[] => { - return transformContextVariables(AlertProvidedActionVariableDescriptions); -}; - -export const getSummaryAlertActionVariables = (): ActionVariable[] => { - return transformContextVariables(SummarizedAlertProvidedActionVariableDescriptions); -}; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/index.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/index.ts index e523c5a6db378..aba75da477557 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/index.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/index.ts @@ -7,6 +7,6 @@ export { templateActionVariable } from './template_action_variable'; export { hasMustacheTokens } from './has_mustache_tokens'; -export { AlertProvidedActionVariables } from './action_variables'; +export type { AlertProvidedActionVariables } from '@kbn/alerts-ui-shared/src/action_variables/action_variables'; export { updateActionConnector, executeAction } from './action_connector_api'; export { isRuleSnoozed } from './is_rule_snoozed'; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx index a2479edf1b5af..2c3feb19561fd 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx @@ -22,13 +22,13 @@ import { EuiText, } from '@elastic/eui'; import { - ActionGroup, RuleActionAlertsFilterProperty, RuleActionFrequency, RuleActionParam, RuleSystemAction, } from '@kbn/alerting-plugin/common'; import { v4 as uuidv4 } from 'uuid'; +import { ActionGroupWithMessageVariables } from '@kbn/triggers-actions-ui-types'; import { TECH_PREVIEW_DESCRIPTION, TECH_PREVIEW_LABEL } from '../translations'; import { loadActionTypes, loadAllActions as loadConnectors } from '../../lib/action_connector_api'; import { @@ -50,13 +50,8 @@ import { DEFAULT_FREQUENCY, VIEW_LICENSE_OPTIONS_LINK } from '../../../common/co import { useKibana } from '../../../common/lib/kibana'; import { ConnectorAddModal } from '.'; import { suspendedComponentWithProps } from '../../lib/suspended_component_with_props'; -import { OmitMessageVariablesType } from '../../lib/action_variables'; import { SystemActionTypeForm } from './system_action_type_form'; -export interface ActionGroupWithMessageVariables extends ActionGroup { - omitMessageVariables?: OmitMessageVariablesType; - defaultActionMessage?: string; -} export interface ActionAccordionFormProps { actions: RuleUiAction[]; defaultActionGroupId: string; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.test.tsx index cbf6c17e78481..de4463721d3de 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.test.tsx @@ -21,13 +21,13 @@ import { EuiFieldText } from '@elastic/eui'; import { I18nProvider, __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render, waitFor, screen } from '@testing-library/react'; import { DEFAULT_FREQUENCY } from '../../../common/constants'; -import { transformActionVariables } from '../../lib/action_variables'; import { RuleNotifyWhen, RuleNotifyWhenType, SanitizedRuleAction, } from '@kbn/alerting-plugin/common'; import { AlertConsumers } from '@kbn/rule-data-utils'; +import { transformActionVariables } from '@kbn/alerts-ui-shared/src/action_variables/transforms'; const CUSTOM_NOTIFY_WHEN_OPTIONS: NotifyWhenSelectOptions[] = [ { @@ -56,8 +56,8 @@ const actionTypeRegistry = actionTypeRegistryMock.create(); jest.mock('../../../common/lib/kibana'); -jest.mock('../../lib/action_variables', () => { - const original = jest.requireActual('../../lib/action_variables'); +jest.mock('@kbn/alerts-ui-shared/src/action_variables/transforms', () => { + const original = jest.requireActual('@kbn/alerts-ui-shared/src/action_variables/transforms'); return { ...original, transformActionVariables: jest.fn(), diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.tsx index 2fcb4367d99eb..b81b24b0806be 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.tsx @@ -44,6 +44,10 @@ import { parseDuration, } from '@kbn/alerting-plugin/common/parse_duration'; import { SavedObjectAttribute } from '@kbn/core-saved-objects-api-server'; +import { transformActionVariables } from '@kbn/alerts-ui-shared/src/action_variables/transforms'; +import { RuleActionsNotifyWhen } from '@kbn/alerts-ui-shared/src/rule_form/rule_actions/rule_actions_notify_when'; +import { RuleActionsAlertsFilterTimeframe } from '@kbn/alerts-ui-shared/src/rule_form/rule_actions/rule_actions_alerts_filter_timeframe'; +import { ActionGroupWithMessageVariables } from '@kbn/triggers-actions-ui-types'; import { TECH_PREVIEW_DESCRIPTION, TECH_PREVIEW_LABEL } from '../translations'; import { getIsExperimentalFeatureEnabled } from '../../../common/get_experimental_features'; import { @@ -58,13 +62,10 @@ import { } from '../../../types'; import { checkActionFormActionTypeEnabled } from '../../lib/check_action_type_enabled'; import { hasSaveActionsCapability } from '../../lib/capabilities'; -import { ActionAccordionFormProps, ActionGroupWithMessageVariables } from './action_form'; -import { transformActionVariables } from '../../lib/action_variables'; +import { ActionAccordionFormProps } from './action_form'; import { useKibana } from '../../../common/lib/kibana'; import { ConnectorsSelection } from './connectors_selection'; -import { ActionNotifyWhen } from './action_notify_when'; import { validateParamsForWarnings } from '../../lib/validate_params_for_warnings'; -import { ActionAlertsFilterTimeframe } from './action_alerts_filter_timeframe'; import { ActionAlertsFilterQuery } from './action_alerts_filter_query'; import { validateActionFilterQuery } from '../../lib/value_validators'; import { useRuleTypeAadTemplateFields } from '../../hooks/use_rule_aad_template_fields'; @@ -154,6 +155,7 @@ export const ActionTypeForm = ({ }: ActionTypeFormProps) => { const { application: { capabilities }, + settings, http, } = useKibana().services; const { euiTheme } = useEuiTheme(); @@ -368,7 +370,7 @@ export const ActionTypeForm = ({ : false; const actionNotifyWhen = ( - - setActionAlertsFilterProperty('timeframe', timeframe, index)} /> diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/system_action_type_form.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/system_action_type_form.test.tsx index ef92d61fbc303..63092931da27a 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/system_action_type_form.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/system_action_type_form.test.tsx @@ -18,8 +18,8 @@ const actionTypeRegistry = actionTypeRegistryMock.create(); jest.mock('../../../common/lib/kibana'); -jest.mock('../../lib/action_variables', () => { - const original = jest.requireActual('../../lib/action_variables'); +jest.mock('@kbn/alerts-ui-shared/src/action_variables/transforms', () => { + const original = jest.requireActual('@kbn/alerts-ui-shared/src/action_variables/transforms'); return { ...original, transformActionVariables: jest.fn(), diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/system_action_type_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/system_action_type_form.tsx index 6e42cc4f886cc..9654835150548 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/system_action_type_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/system_action_type_form.tsx @@ -26,6 +26,8 @@ import { } from '@elastic/eui'; import { isEmpty, partition, some } from 'lodash'; import { ActionVariable, RuleActionParam } from '@kbn/alerting-plugin/common'; +import { ActionGroupWithMessageVariables } from '@kbn/triggers-actions-ui-types'; +import { transformActionVariables } from '@kbn/alerts-ui-shared/src/action_variables/transforms'; import { TECH_PREVIEW_DESCRIPTION, TECH_PREVIEW_LABEL } from '../translations'; import { IErrorObject, @@ -36,8 +38,7 @@ import { ActionTypeRegistryContract, ActionConnectorMode, } from '../../../types'; -import { ActionAccordionFormProps, ActionGroupWithMessageVariables } from './action_form'; -import { transformActionVariables } from '../../lib/action_variables'; +import { ActionAccordionFormProps } from './action_form'; import { useKibana } from '../../../common/lib/kibana'; import { validateParamsForWarnings } from '../../lib/validate_params_for_warnings'; import { useRuleTypeAadTemplateFields } from '../../hooks/use_rule_aad_template_fields'; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_add.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_add.test.tsx index 5c5e8b8ca7d67..df5fb10129fee 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_add.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_add.test.tsx @@ -7,9 +7,9 @@ import { v4 as uuidv4 } from 'uuid'; import React, { FunctionComponent } from 'react'; -import { mountWithIntl, nextTick } from '@kbn/test-jest-helpers'; -import { act } from 'react-dom/test-utils'; import { FormattedMessage } from '@kbn/i18n-react'; +import { render, screen, within } from '@testing-library/react'; + import { EuiFormLabel } from '@elastic/eui'; import { coreMock } from '@kbn/core/public/mocks'; import RuleAdd from './rule_add'; @@ -29,7 +29,6 @@ import { RuleTypeModel, } from '../../../types'; import { ruleTypeRegistryMock } from '../../rule_type_registry.mock'; -import { ReactWrapper } from 'enzyme'; import { ALERTING_FEATURE_ID } from '@kbn/alerting-plugin/common'; import { useKibana } from '../../../common/lib/kibana'; @@ -38,6 +37,8 @@ import { fetchUiHealthStatus } from '@kbn/alerts-ui-shared/src/common/apis/fetch import { loadActionTypes, loadAllActions } from '../../lib/action_connector_api'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { waitFor } from '@testing-library/react'; +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; +import userEvent from '@testing-library/user-event'; jest.mock('../../../common/lib/kibana'); jest.mock('../../lib/rule_api/rule_types', () => ({ @@ -81,8 +82,7 @@ export const TestExpression: FunctionComponent = () => { ); }; -// FLAKY: https://github.com/elastic/kibana/issues/174397 -describe.skip('rule_add', () => { +describe('rule_add', () => { afterEach(() => { jest.clearAllMocks(); }); @@ -90,7 +90,6 @@ describe.skip('rule_add', () => { afterAll(() => { jest.resetAllMocks(); }); - let wrapper: ReactWrapper; async function setup({ initialValues, @@ -195,51 +194,46 @@ describe.skip('rule_add', () => { actionTypeRegistry.list.mockReturnValue([actionTypeModel]); actionTypeRegistry.has.mockReturnValue(true); - wrapper = mountWithIntl( - - { - return new Promise(() => {}); - }} - actionTypeRegistry={actionTypeRegistry} - ruleTypeRegistry={ruleTypeRegistry} - metadata={{ test: 'some value', fields: ['test'] }} - ruleTypeId={ruleTypeId} - validConsumers={validConsumers} - /> - - ); - - // Wait for active space to resolve before requesting the component to update - await act(async () => { - await nextTick(); - wrapper.update(); - }); + return { + consumer: ALERTING_FEATURE_ID, + onClose, + initialValues, + onSave: () => { + return new Promise(() => {}); + }, + actionTypeRegistry, + ruleTypeRegistry, + metadata: { test: 'some value', fields: ['test'] }, + ruleTypeId, + validConsumers, + }; } it('renders rule add flyout', async () => { (fetchUiConfig as jest.Mock).mockResolvedValue({ minimumScheduleInterval: { value: '1m', enforce: false }, }); + const onClose = jest.fn(); - await setup({ + const props = await setup({ initialValues: {}, onClose, }); - await act(async () => { - await nextTick(); - wrapper.update(); - }); + render( + + + + + + ); + + expect(await screen.findByTestId('addRuleFlyoutTitle')).toBeInTheDocument(); - expect(wrapper.find('[data-test-subj="addRuleFlyoutTitle"]').exists()).toBeTruthy(); - expect(wrapper.find('[data-test-subj="saveRuleButton"]').exists()).toBeTruthy(); - expect(wrapper.find('[data-test-subj="showRequestButton"]').exists()).toBeTruthy(); + expect(await screen.findByTestId('saveRuleButton')).toBeInTheDocument(); + expect(await screen.findByTestId('showRequestButton')).toBeInTheDocument(); - wrapper.find('[data-test-subj="cancelSaveRuleButton"]').last().simulate('click'); + userEvent.click(await screen.findByTestId('cancelSaveRuleButton')); expect(onClose).toHaveBeenCalledWith(RuleFlyoutCloseReason.CANCELED, { fields: ['test'], test: 'some value', @@ -251,25 +245,23 @@ describe.skip('rule_add', () => { minimumScheduleInterval: { value: '1m', enforce: false }, }); const onClose = jest.fn(); - await setup({ + const props = await setup({ initialValues: {}, onClose, }); - await act(async () => { - await nextTick(); - wrapper.update(); - }); + render( + + + + + + ); - await waitFor(() => { - const ruleTypesContainer = wrapper.find('[data-test-subj="ruleGroupTypeSelectContainer"]'); - const ruleTypeButton = ruleTypesContainer - .render() - .find('[data-test-subj="my-rule-type-SelectOption"]'); + expect(await screen.findByTestId('my-rule-type-SelectOption')).toBeInTheDocument(); - expect(ruleTypeButton.length).toEqual(1); - expect(ruleTypeButton.text()).toMatchInlineSnapshot(`"Testtest"`); - }); + expect(await screen.findByText('Test')).toBeInTheDocument(); + expect(await screen.findByText('test')).toBeInTheDocument(); }); it('renders a confirm close modal if the flyout is closed after inputs have changed', async () => { @@ -277,31 +269,33 @@ describe.skip('rule_add', () => { minimumScheduleInterval: { value: '1m', enforce: false }, }); const onClose = jest.fn(); - await setup({ + + const props = await setup({ initialValues: {}, onClose, ruleTypeId: 'my-rule-type', }); - await act(async () => { - await nextTick(); - wrapper.update(); - }); + render( + + + + + + ); - wrapper - .find('input#ruleName') - .at(0) - .simulate('change', { target: { value: 'my rule type' } }); + expect(await screen.findByTestId('ruleNameInput')).toBeInTheDocument(); - await waitFor(() => { - expect(wrapper.find('input#ruleName').props().value).toBe('my rule type'); - expect(wrapper.find('[data-test-subj="tagsComboBox"]').first().text()).toBe(''); - expect(wrapper.find('.euiSelect').first().props().value).toBe('m'); + userEvent.type(await screen.findByTestId('ruleNameInput'), 'my{space}rule{space}type'); - wrapper.find('[data-test-subj="cancelSaveRuleButton"]').last().simulate('click'); - expect(onClose).not.toHaveBeenCalled(); - expect(wrapper.find('[data-test-subj="confirmRuleCloseModal"]').exists()).toBe(true); - }); + expect(await screen.findByTestId('ruleNameInput')).toHaveValue('my rule type'); + expect(await screen.findByTestId('comboBoxSearchInput')).toHaveValue(''); + expect(await screen.findByTestId('intervalInputUnit')).toHaveValue('m'); + + userEvent.click(await screen.findByTestId('cancelSaveRuleButton')); + + expect(onClose).not.toHaveBeenCalled(); + expect(await screen.findByTestId('confirmRuleCloseModal')).toBeInTheDocument(); }); it('renders rule add flyout with initial values', async () => { @@ -309,7 +303,7 @@ describe.skip('rule_add', () => { minimumScheduleInterval: { value: '1m', enforce: false }, }); const onClose = jest.fn(); - await setup({ + const props = await setup({ initialValues: { name: 'Simple status rule', tags: ['uptime', 'logs'], @@ -321,28 +315,61 @@ describe.skip('rule_add', () => { ruleTypeId: 'my-rule-type', }); - expect(wrapper.find('input#ruleName').props().value).toBe('Simple status rule'); - expect(wrapper.find('[data-test-subj="tagsComboBox"]').first().text()).toBe('uptimelogs'); - expect(wrapper.find('[data-test-subj="intervalInput"]').first().props().value).toEqual(1); - expect(wrapper.find('[data-test-subj="intervalInputUnit"]').first().props().value).toBe('h'); + render( + + + + + + ); + + expect(await screen.findByTestId('ruleNameInput')).toHaveValue('Simple status rule'); + + expect( + await within(await screen.findByTestId('tagsComboBox')).findByText('uptime') + ).toBeInTheDocument(); + expect( + await within(await screen.findByTestId('tagsComboBox')).findByText('logs') + ).toBeInTheDocument(); + + expect(await screen.findByTestId('intervalInput')).toHaveValue(1); + expect(await screen.findByTestId('intervalInputUnit')).toHaveValue('h'); }); it('renders rule add flyout with DEFAULT_RULE_INTERVAL if no initialValues specified and no minimumScheduleInterval', async () => { (fetchUiConfig as jest.Mock).mockResolvedValue({}); - await setup({ ruleTypeId: 'my-rule-type' }); + const props = await setup({ ruleTypeId: 'my-rule-type' }); + + render( + + + + + + ); - expect(wrapper.find('[data-test-subj="intervalInput"]').first().props().value).toEqual(1); - expect(wrapper.find('[data-test-subj="intervalInputUnit"]').first().props().value).toBe('m'); + expect(await screen.findByTestId('intervalInput')).toHaveValue(1); + + expect(await screen.findByTestId('intervalInputUnit')).toHaveValue('m'); }); it('renders rule add flyout with minimumScheduleInterval if minimumScheduleInterval is greater than DEFAULT_RULE_INTERVAL', async () => { (fetchUiConfig as jest.Mock).mockResolvedValue({ minimumScheduleInterval: { value: '5m', enforce: false }, }); - await setup({ ruleTypeId: 'my-rule-type' }); + const props = await setup({ ruleTypeId: 'my-rule-type' }); + + render( + + + + + + ); + + expect(await screen.findByTestId('intervalInput')).toHaveValue(5); - expect(wrapper.find('[data-test-subj="intervalInput"]').first().props().value).toEqual(5); - expect(wrapper.find('[data-test-subj="intervalInputUnit"]').first().props().value).toBe('m'); + expect(await screen.findByTestId('intervalInputUnit')).toHaveValue('m'); }); it('emit an onClose event when the rule is saved', async () => { @@ -354,7 +381,7 @@ describe.skip('rule_add', () => { (createRule as jest.MockedFunction).mockResolvedValue(rule); - await setup({ + const props = await setup({ initialValues: { name: 'Simple status rule', ruleTypeId: 'my-rule-type', @@ -366,17 +393,23 @@ describe.skip('rule_add', () => { onClose, }); - wrapper.find('[data-test-subj="saveRuleButton"]').last().simulate('click'); + render( + + + + + + ); - // Wait for handlers to fire - await act(async () => { - await nextTick(); - wrapper.update(); - }); + expect(await screen.findByTestId('saveRuleButton')).toBeInTheDocument(); - expect(onClose).toHaveBeenCalledWith(RuleFlyoutCloseReason.SAVED, { - test: 'some value', - fields: ['test'], + userEvent.click(await screen.findByTestId('saveRuleButton')); + + await waitFor(() => { + return expect(onClose).toHaveBeenCalledWith(RuleFlyoutCloseReason.SAVED, { + test: 'some value', + fields: ['test'], + }); }); }); @@ -385,7 +418,7 @@ describe.skip('rule_add', () => { minimumScheduleInterval: { value: '1m', enforce: false }, }); const onClose = jest.fn(); - await setup({ + const props = await setup({ initialValues: { name: 'Simple rule', consumer: 'alerts', @@ -435,23 +468,19 @@ describe.skip('rule_add', () => { validConsumers: [AlertConsumers.INFRASTRUCTURE, AlertConsumers.LOGS], }); - await act(async () => { - await nextTick(); - wrapper.update(); - }); - - expect(wrapper.find('[data-test-subj="addRuleFlyoutTitle"]').exists()).toBeTruthy(); - expect(wrapper.find('[data-test-subj="saveRuleButton"]').exists()).toBeTruthy(); + render( + + + + + + ); - wrapper.find('[data-test-subj="saveRuleButton"]').last().simulate('click'); + expect(await screen.findByTestId('saveRuleButton')).toBeInTheDocument(); - await act(async () => { - await nextTick(); - wrapper.update(); - }); - - await waitFor(() => { - expect(createRule).toHaveBeenLastCalledWith( + await waitFor(async () => { + userEvent.click(await screen.findByTestId('saveRuleButton')); + return expect(createRule).toHaveBeenLastCalledWith( expect.objectContaining({ rule: expect.objectContaining({ consumer: 'logs', @@ -465,7 +494,7 @@ describe.skip('rule_add', () => { (fetchUiConfig as jest.Mock).mockResolvedValue({ minimumScheduleInterval: { value: '1m', enforce: false }, }); - await setup({ + const props = await setup({ initialValues: { ruleTypeId: 'my-rule-type' }, onClose: jest.fn(), defaultScheduleInterval: '3h', @@ -473,22 +502,17 @@ describe.skip('rule_add', () => { actionsShow: true, }); - // Wait for handlers to fire - await act(async () => { - await nextTick(); - wrapper.update(); - }); + render( + + + + + + ); - await waitFor(() => { - const intervalInputUnit = wrapper - .find('[data-test-subj="intervalInputUnit"]') - .first() - .getElement().props.value; - const intervalInput = wrapper.find('[data-test-subj="intervalInput"]').first().getElement() - .props.value; - expect(intervalInputUnit).toBe('h'); - expect(intervalInput).toBe(3); - }); + expect(await screen.findByTestId('intervalInputUnit')).toHaveValue('h'); + + expect(await screen.findByTestId('intervalInput')).toHaveValue(3); }); it('should load connectors and connector types when there is a pre-selected rule type', async () => { @@ -496,18 +520,20 @@ describe.skip('rule_add', () => { minimumScheduleInterval: { value: '1m', enforce: false }, }); - await setup({ + const props = await setup({ initialValues: {}, onClose: jest.fn(), ruleTypeId: 'my-rule-type', actionsShow: true, }); - // Wait for handlers to fire - await act(async () => { - await nextTick(); - wrapper.update(); - }); + render( + + + + + + ); await waitFor(() => { expect(fetchUiHealthStatus).toHaveBeenCalledTimes(1); @@ -526,28 +552,33 @@ describe.skip('rule_add', () => { hasPermanentEncryptionKey: false, }); - await setup({ + const props = await setup({ initialValues: {}, onClose: jest.fn(), ruleTypeId: 'my-rule-type', actionsShow: true, }); - // Wait for handlers to fire - await act(async () => { - await nextTick(); - wrapper.update(); - }); + render( + + + + + + ); await waitFor(() => { expect(fetchUiHealthStatus).toHaveBeenCalledTimes(1); expect(fetchAlertingFrameworkHealth).toHaveBeenCalledTimes(1); expect(loadActionTypes).not.toHaveBeenCalled(); expect(loadAllActions).not.toHaveBeenCalled(); - expect(wrapper.find('[data-test-subj="actionNeededEmptyPrompt"]').first().text()).toContain( - 'You must configure an encryption key to use Alerting' - ); }); + + expect( + await screen.findByText('You must configure an encryption key to use Alerting.', { + collapseWhitespace: false, + }) + ).toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form_consumer_selection.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form_consumer_selection.tsx index 0aa75964a153c..455d8af91e341 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form_consumer_selection.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form_consumer_selection.tsx @@ -81,7 +81,7 @@ const SINGLE_SELECTION = { asPlainText: true }; export const RuleFormConsumerSelection = (props: RuleFormConsumerSelectionProps) => { const { consumers, errors, onChange, selectedConsumer, initialSelectedConsumer } = props; - const isInvalid = errors?.consumer?.length > 0; + const isInvalid = (errors?.consumer as string[])?.length > 0; const handleOnChange = useCallback( (selected: Array>) => { if (selected.length > 0) { diff --git a/x-pack/plugins/triggers_actions_ui/public/common/constants/index.ts b/x-pack/plugins/triggers_actions_ui/public/common/constants/index.ts index 1398b33e787b8..ad559429df728 100644 --- a/x-pack/plugins/triggers_actions_ui/public/common/constants/index.ts +++ b/x-pack/plugins/triggers_actions_ui/public/common/constants/index.ts @@ -21,7 +21,10 @@ export const VIEW_LICENSE_OPTIONS_LINK = 'https://www.elastic.co/subscriptions'; export const PLUGIN_ID = 'triggersActions'; export const ALERTS_PAGE_ID = 'triggersActionsAlerts'; export const CONNECTORS_PLUGIN_ID = 'triggersActionsConnectors'; -export * from './i18n_weekdays'; +export { + I18N_WEEKDAY_OPTIONS, + I18N_WEEKDAY_OPTIONS_DDD, +} from '@kbn/alerts-ui-shared/src/common/constants/i18n_weekdays'; export const builtInComparators: { [key: string]: Comparator } = { [COMPARATORS.GREATER_THAN]: { diff --git a/x-pack/plugins/triggers_actions_ui/public/index.ts b/x-pack/plugins/triggers_actions_ui/public/index.ts index 3f00b4ffb8ae5..5fae33e1d2206 100644 --- a/x-pack/plugins/triggers_actions_ui/public/index.ts +++ b/x-pack/plugins/triggers_actions_ui/public/index.ts @@ -86,13 +86,14 @@ export { } from './application/components'; export { - AlertProvidedActionVariables, hasMustacheTokens, templateActionVariable, updateActionConnector, executeAction, } from './application/lib'; +export { AlertProvidedActionVariables } from '@kbn/alerts-ui-shared/src/action_variables/action_variables'; + export type { ActionGroupWithCondition } from './application/sections'; export { AlertConditions, AlertConditionsGroup } from './application/sections'; diff --git a/x-pack/plugins/upgrade_assistant/server/plugin.ts b/x-pack/plugins/upgrade_assistant/server/plugin.ts index a2753279e8f69..3df9f7deced9d 100644 --- a/x-pack/plugins/upgrade_assistant/server/plugin.ts +++ b/x-pack/plugins/upgrade_assistant/server/plugin.ts @@ -18,7 +18,7 @@ import { import { SecurityPluginStart } from '@kbn/security-plugin/server'; import { LogsSharedPluginSetup } from '@kbn/logs-shared-plugin/server'; -import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { SecurityPluginSetup } from '@kbn/security-plugin/server'; import { LicensingPluginSetup } from '@kbn/licensing-plugin/server'; import { DEPRECATION_LOGS_SOURCE_ID, DEPRECATION_LOGS_INDEX } from '../common/constants'; diff --git a/x-pack/plugins/watcher/server/types.ts b/x-pack/plugins/watcher/server/types.ts index d0800947fb50f..683353359a55e 100644 --- a/x-pack/plugins/watcher/server/types.ts +++ b/x-pack/plugins/watcher/server/types.ts @@ -8,7 +8,7 @@ import { SemVer } from 'semver'; import type { IRouter } from '@kbn/core/server'; -import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { LicensingPluginSetup, LicensingPluginStart } from '@kbn/licensing-plugin/server'; import { License, handleEsError } from './shared_imports'; diff --git a/x-pack/test/alerting_api_integration/common/plugins/actions_simulators/server/plugin.ts b/x-pack/test/alerting_api_integration/common/plugins/actions_simulators/server/plugin.ts index 155bb96be9461..8d39ed65f460f 100644 --- a/x-pack/test/alerting_api_integration/common/plugins/actions_simulators/server/plugin.ts +++ b/x-pack/test/alerting_api_integration/common/plugins/actions_simulators/server/plugin.ts @@ -10,7 +10,7 @@ import https from 'https'; import { Plugin, CoreSetup } from '@kbn/core/server'; import { schema } from '@kbn/config-schema'; import { EncryptedSavedObjectsPluginStart } from '@kbn/encrypted-saved-objects-plugin/server'; -import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { PluginSetupContract as ActionsPluginSetupContract, PluginStartContract as ActionsPluginStartContract, diff --git a/x-pack/test/alerting_api_integration/common/plugins/alerts/server/plugin.ts b/x-pack/test/alerting_api_integration/common/plugins/alerts/server/plugin.ts index 4cafa57d3d480..9648ffdbde973 100644 --- a/x-pack/test/alerting_api_integration/common/plugins/alerts/server/plugin.ts +++ b/x-pack/test/alerting_api_integration/common/plugins/alerts/server/plugin.ts @@ -17,7 +17,7 @@ import { TaskManagerStartContract, } from '@kbn/task-manager-plugin/server/plugin'; import { EncryptedSavedObjectsPluginStart } from '@kbn/encrypted-saved-objects-plugin/server'; -import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { SpacesPluginStart } from '@kbn/spaces-plugin/server'; import { SecurityPluginStart } from '@kbn/security-plugin/server'; import { PluginStartContract as ActionsPluginStart } from '@kbn/actions-plugin/server'; diff --git a/x-pack/test/alerting_api_integration/common/plugins/alerts_restricted/server/plugin.ts b/x-pack/test/alerting_api_integration/common/plugins/alerts_restricted/server/plugin.ts index 9e78728d1f7a8..3b1ee7ed9cf14 100644 --- a/x-pack/test/alerting_api_integration/common/plugins/alerts_restricted/server/plugin.ts +++ b/x-pack/test/alerting_api_integration/common/plugins/alerts_restricted/server/plugin.ts @@ -9,7 +9,7 @@ import { Plugin, CoreSetup } from '@kbn/core/server'; import { PluginSetupContract as ActionsPluginSetup } from '@kbn/actions-plugin/server/plugin'; import { PluginSetupContract as AlertingPluginSetup } from '@kbn/alerting-plugin/server/plugin'; import { EncryptedSavedObjectsPluginStart } from '@kbn/encrypted-saved-objects-plugin/server'; -import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; import { defineAlertTypes } from './alert_types'; diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/backfill/find.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/backfill/find.ts index 1a6d94a7ffafb..3b2e049a53e05 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/backfill/find.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/backfill/find.ts @@ -135,7 +135,8 @@ export default function findBackfillTests({ getService }: FtrProviderContext) { for (const scenario of UserAtSpaceScenarios) { const { user, space } = scenario; - describe(scenario.id, () => { + // FLAKY: https://github.com/elastic/kibana/issues/181862 + describe.skip(scenario.id, () => { const apiOptions = { spaceId: space.id, username: user.username, diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts index 93c8cd40fb37f..65a325b46fce2 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts @@ -12,14 +12,7 @@ import { bedrockClaude2SuccessResponse, } from '@kbn/actions-simulators-plugin/server/bedrock_simulation'; import { DEFAULT_TOKEN_LIMIT } from '@kbn/stack-connectors-plugin/common/bedrock/constants'; -import { PassThrough } from 'stream'; -import { EventStreamCodec } from '@smithy/eventstream-codec'; -import { fromUtf8, toUtf8 } from '@smithy/util-utf8'; import { TaskErrorSource } from '@kbn/task-manager-plugin/common'; -import { - ELASTIC_HTTP_VERSION_HEADER, - X_ELASTIC_INTERNAL_ORIGIN_REQUEST, -} from '@kbn/core-http-common'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; import { getUrlPrefix, ObjectRemover } from '../../../../../common/lib'; @@ -432,38 +425,6 @@ export default function bedrockTest({ getService }: FtrProviderContext) { }); }); - it('should invoke stream with assistant AI body argument formatted to bedrock expectations', async () => { - await new Promise((resolve, reject) => { - const passThrough = new PassThrough(); - - supertest - .post(`/internal/elastic_assistant/actions/connector/${bedrockActionId}/_execute`) - .set('kbn-xsrf', 'foo') - .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') - .on('error', reject) - .send({ - actionTypeId: '.bedrock', - subAction: 'invokeStream', - message: 'Hello world', - isEnabledKnowledgeBase: false, - isEnabledRAGAlerts: false, - replacements: {}, - }) - .pipe(passThrough); - const responseBuffer: Uint8Array[] = []; - passThrough.on('data', (chunk) => { - responseBuffer.push(chunk); - }); - - passThrough.on('end', () => { - const parsed = parseBedrockBuffer(responseBuffer); - expect(parsed).to.eql('Hello world, what a unique string!'); - resolve(); - }); - }); - }); - describe('Token tracking dashboard', () => { const dashboardId = 'specific-dashboard-id-default'; @@ -647,46 +608,3 @@ export default function bedrockTest({ getService }: FtrProviderContext) { }); }); } - -const parseBedrockBuffer = (chunks: Uint8Array[]): string => { - let bedrockBuffer: Uint8Array = new Uint8Array(0); - - return chunks - .map((chunk) => { - bedrockBuffer = concatChunks(bedrockBuffer, chunk); - let messageLength = getMessageLength(bedrockBuffer); - const buildChunks = []; - while (bedrockBuffer.byteLength > 0 && bedrockBuffer.byteLength >= messageLength) { - const extractedChunk = bedrockBuffer.slice(0, messageLength); - buildChunks.push(extractedChunk); - bedrockBuffer = bedrockBuffer.slice(messageLength); - messageLength = getMessageLength(bedrockBuffer); - } - - const awsDecoder = new EventStreamCodec(toUtf8, fromUtf8); - - return buildChunks - .map((bChunk) => { - const event = awsDecoder.decode(bChunk); - const body = JSON.parse( - Buffer.from(JSON.parse(new TextDecoder().decode(event.body)).bytes, 'base64').toString() - ); - return body.delta.text; - }) - .join(''); - }) - .join(''); -}; - -function concatChunks(a: Uint8Array, b: Uint8Array): Uint8Array { - const newBuffer = new Uint8Array(a.length + b.length); - newBuffer.set(a); - newBuffer.set(b, a.length); - return newBuffer; -} - -function getMessageLength(buffer: Uint8Array): number { - if (buffer.byteLength === 0) return 0; - const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength); - return view.getUint32(0, false); -} diff --git a/x-pack/test/api_integration/apis/management/advanced_settings/feature_controls.ts b/x-pack/test/api_integration/apis/management/advanced_settings/feature_controls.ts index 4af49a3991611..61570f83aed46 100644 --- a/x-pack/test/api_integration/apis/management/advanced_settings/feature_controls.ts +++ b/x-pack/test/api_integration/apis/management/advanced_settings/feature_controls.ts @@ -78,7 +78,8 @@ export default function featureControlsTests({ getService }: FtrProviderContext) .catch((error: any) => ({ error, response: undefined })); } - describe('feature controls', () => { + // Failing: See https://github.com/elastic/kibana/issues/176445 + describe.skip('feature controls', () => { it(`settings can be saved with the advancedSettings: ["all"] feature privilege`, async () => { const username = 'settings_all'; const roleName = 'settings_all'; diff --git a/x-pack/test/api_integration/apis/slos/create_slo.ts b/x-pack/test/api_integration/apis/slos/create_slo.ts index f6fa12fe3d8ba..4b458558b233e 100644 --- a/x-pack/test/api_integration/apis/slos/create_slo.ts +++ b/x-pack/test/api_integration/apis/slos/create_slo.ts @@ -142,24 +142,15 @@ export default function ({ getService }: FtrProviderContext) { ], }, }, - runtime_mappings: { - 'slo.id': { - type: 'keyword', - script: { source: `emit('${id}')` }, - }, - 'slo.revision': { type: 'long', script: { source: 'emit(1)' } }, - }, }, dest: { index: '.slo-observability.sli-v3.3', - pipeline: '.slo-observability.sli.pipeline-v3.3', + pipeline: `.slo-observability.sli.pipeline-${id}-1`, }, frequency: '1m', sync: { time: { field: '@timestamp', delay: '1m' } }, pivot: { group_by: { - 'slo.id': { terms: { field: 'slo.id' } }, - 'slo.revision': { terms: { field: 'slo.revision' } }, 'slo.groupings.tags': { terms: { field: 'tags' } }, '@timestamp': { date_histogram: { field: '@timestamp', fixed_interval: '1m' } }, }, diff --git a/x-pack/test/api_integration/apis/slos/update_slo.ts b/x-pack/test/api_integration/apis/slos/update_slo.ts index b8f4a14654d4d..76e19d6ba20a0 100644 --- a/x-pack/test/api_integration/apis/slos/update_slo.ts +++ b/x-pack/test/api_integration/apis/slos/update_slo.ts @@ -146,24 +146,15 @@ export default function ({ getService }: FtrProviderContext) { ], }, }, - runtime_mappings: { - 'slo.id': { - type: 'keyword', - script: { source: `emit('${id}')` }, - }, - 'slo.revision': { type: 'long', script: { source: 'emit(2)' } }, - }, }, dest: { index: '.slo-observability.sli-v3.3', - pipeline: '.slo-observability.sli.pipeline-v3.3', + pipeline: `.slo-observability.sli.pipeline-${id}-2`, }, frequency: '1m', sync: { time: { field: '@timestamp', delay: '1m' } }, pivot: { group_by: { - 'slo.id': { terms: { field: 'slo.id' } }, - 'slo.revision': { terms: { field: 'slo.revision' } }, 'slo.groupings.hosts': { terms: { field: 'hosts' } }, '@timestamp': { date_histogram: { field: '@timestamp', fixed_interval: '1m' } }, }, diff --git a/x-pack/test/api_integration/services/security_solution_api.gen.ts b/x-pack/test/api_integration/services/security_solution_api.gen.ts index bc080f46906e9..f5089b489a617 100644 --- a/x-pack/test/api_integration/services/security_solution_api.gen.ts +++ b/x-pack/test/api_integration/services/security_solution_api.gen.ts @@ -80,7 +80,9 @@ export function SecuritySolutionApiProvider({ getService }: FtrProviderContext) /** * Migrations favor data integrity over shard size. Consequently, unused or orphaned indices are artifacts of the migration process. A successful migration will result in both the old and new indices being present. -As such, the old, orphaned index can (and likely should) be deleted. While you can delete these indices manually, +As such, the old, orphaned index can (and likely should) be deleted. + +While you can delete these indices manually, the endpoint accomplishes this task by applying a deletion policy to the relevant index, causing it to be deleted after 30 days. It also deletes other artifacts specific to the migration implementation. @@ -94,7 +96,7 @@ after 30 days. It also deletes other artifacts specific to the migration impleme .send(props.body as object); }, /** - * Creates new detection rules in bulk. + * Create new detection rules in bulk. */ bulkCreateRules(props: BulkCreateRulesProps) { return supertest @@ -105,7 +107,7 @@ after 30 days. It also deletes other artifacts specific to the migration impleme .send(props.body as object); }, /** - * Deletes multiple rules. + * Delete detection rules in bulk. */ bulkDeleteRules(props: BulkDeleteRulesProps) { return supertest @@ -127,7 +129,7 @@ after 30 days. It also deletes other artifacts specific to the migration impleme .send(props.body as object); }, /** - * Updates multiple rules using the `PATCH` method. + * Update specific fields of existing detection rules using the `rule_id` or `id` field. */ bulkPatchRules(props: BulkPatchRulesProps) { return supertest @@ -138,8 +140,11 @@ after 30 days. It also deletes other artifacts specific to the migration impleme .send(props.body as object); }, /** - * Updates multiple rules using the `PUT` method. - */ + * Update multiple detection rules using the `rule_id` or `id` field. The original rules are replaced, and all unspecified fields are deleted. +> info +> You cannot modify the `id` or `rule_id` values. + + */ bulkUpdateRules(props: BulkUpdateRulesProps) { return supertest .put('/api/detection_engine/rules/_bulk_update') @@ -155,6 +160,11 @@ after 30 days. It also deletes other artifacts specific to the migration impleme .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana'); }, + /** + * Initiate a migration of detection alerts. +Migrations are initiated per index. While the process is neither destructive nor interferes with existing data, it may be resource-intensive. As such, it is recommended that you plan your migrations accordingly. + + */ createAlertsMigration(props: CreateAlertsMigrationProps) { return supertest .post('/api/detection_engine/signals/migration') @@ -164,7 +174,7 @@ after 30 days. It also deletes other artifacts specific to the migration impleme .send(props.body as object); }, /** - * Create a single detection rule + * Create a new detection rule. */ createRule(props: CreateRuleProps) { return supertest @@ -192,7 +202,7 @@ after 30 days. It also deletes other artifacts specific to the migration impleme .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana'); }, /** - * Deletes a single rule using the `rule_id` or `id` field. + * Delete a detection rule using the `rule_id` or `id` field. */ deleteRule(props: DeleteRuleProps) { return supertest @@ -219,8 +229,13 @@ after 30 days. It also deletes other artifacts specific to the migration impleme .send(props.body as object); }, /** - * Exports rules to an `.ndjson` file. The following configuration items are also included in the `.ndjson` file - Actions, Exception lists. Prebuilt rules cannot be exported. - */ + * Export detection rules to an `.ndjson` file. The following configuration items are also included in the `.ndjson` file: +- Actions +- Exception lists +> info +> You cannot export prebuilt rules. + + */ exportRules(props: ExportRulesProps) { return supertest .post('/api/detection_engine/rules/_export') @@ -231,7 +246,7 @@ after 30 days. It also deletes other artifacts specific to the migration impleme .query(props.query); }, /** - * The finalization endpoint replaces the original index's alias with the successfully migrated index's alias. + * Finalize successful migrations of detection alerts. This replaces the original index's alias with the successfully migrated index's alias. The endpoint is idempotent; therefore, it can safely be used to poll a given migration and, upon completion, finalize it. @@ -245,7 +260,7 @@ finalize it. .send(props.body as object); }, /** - * Finds rules that match the given query. + * Retrieve a paginated list of detection rules. By default, the first page is returned, with 20 results per page. */ findRules(props: FindRulesProps) { return supertest @@ -270,6 +285,9 @@ finalize it. .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana'); }, + /** + * Retrieve indices that contain detection alerts of a particular age, along with migration information for each of those indices. + */ getAlertsMigrationStatus(props: GetAlertsMigrationStatusProps) { return supertest .post('/api/detection_engine/signals/migration_status') @@ -294,6 +312,9 @@ finalize it. .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .query(props.query); }, + /** + * Retrieve the status of all Elastic prebuilt detection rules and Timelines. + */ getPrebuiltRulesAndTimelinesStatus() { return supertest .get('/api/detection_engine/rules/prepackaged/_status') @@ -345,8 +366,11 @@ detection engine rules. .query(props.query); }, /** - * Imports rules from an `.ndjson` file, including actions and exception lists. - */ + * Import detection rules from an `.ndjson` file, including actions and exception lists. The request must include: +- The `Content-Type: multipart/form-data` HTTP header. +- A link to the `.ndjson` file containing the rules. + + */ importRules(props: ImportRulesProps) { return supertest .post('/api/detection_engine/rules/_import') @@ -355,6 +379,9 @@ detection engine rules. .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .query(props.query); }, + /** + * Install and update all Elastic prebuilt detection rules and Timelines. + */ installPrebuiltRulesAndTimelines() { return supertest .put('/api/detection_engine/rules/prepackaged') @@ -362,6 +389,12 @@ detection engine rules. .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana'); }, + /** + * And tags to detection alerts, and remove them from alerts. +> info +> You cannot add and remove the same alert tag in the same request. + + */ manageAlertTags(props: ManageAlertTagsProps) { return supertest .post('/api/detection_engine/signals/tags') @@ -371,7 +404,7 @@ detection engine rules. .send(props.body as object); }, /** - * Patch a single rule + * Update specific fields of an existing detection rule using the `rule_id` or `id` field. */ patchRule(props: PatchRuleProps) { return supertest @@ -382,7 +415,7 @@ detection engine rules. .send(props.body as object); }, /** - * The bulk action is applied to all rules that match the filter or to the list of rules by their IDs. + * Apply a bulk action, such as bulk edit, duplicate, or delete, to multiple detection rules. The bulk action is applied to all rules that match the query or to the rules listed by their IDs. */ performBulkAction(props: PerformBulkActionProps) { return supertest @@ -394,7 +427,7 @@ detection engine rules. .query(props.query); }, /** - * Read a single rule + * Retrieve a detection rule using the `rule_id` or `id` field. */ readRule(props: ReadRuleProps) { return supertest @@ -404,6 +437,9 @@ detection engine rules. .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .query(props.query); }, + /** + * List all unique tags from all detection rules. + */ readTags() { return supertest .get('/api/detection_engine/tags') @@ -419,6 +455,9 @@ detection engine rules. .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .send(props.body as object); }, + /** + * Find and/or aggregate detection alerts that match the given query. + */ searchAlerts(props: SearchAlertsProps) { return supertest .post('/api/detection_engine/signals/search') @@ -428,8 +467,11 @@ detection engine rules. .send(props.body as object); }, /** - * Assigns users to alerts. - */ + * Assign users to detection alerts, and unassign them from alerts. +> info +> You cannot add and remove the same assignee in the same request. + + */ setAlertAssignees(props: SetAlertAssigneesProps) { return supertest .post('/api/detection_engine/signals/assignees') @@ -438,6 +480,9 @@ detection engine rules. .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .send(props.body as object); }, + /** + * Set the status of one or more detection alerts. + */ setAlertsStatus(props: SetAlertsStatusProps) { return supertest .post('/api/detection_engine/signals/status') @@ -458,8 +503,11 @@ detection engine rules. .query(props.query); }, /** - * Update a single rule - */ + * Update a detection rule using the `rule_id` or `id` field. The original rule is replaced, and all unspecified fields are deleted. +> info +> You cannot modify the `id` or `rule_id` values. + + */ updateRule(props: UpdateRuleProps) { return supertest .put('/api/detection_engine/rules') diff --git a/x-pack/test/api_integration/services/security_solution_exceptions_api.gen.ts b/x-pack/test/api_integration/services/security_solution_exceptions_api.gen.ts index af4cad1edc90c..31c880d97c8f1 100644 --- a/x-pack/test/api_integration/services/security_solution_exceptions_api.gen.ts +++ b/x-pack/test/api_integration/services/security_solution_exceptions_api.gen.ts @@ -122,7 +122,7 @@ export function SecuritySolutionApiProvider({ getService }: FtrProviderContext) }, findExceptionLists(props: FindExceptionListsProps) { return supertest - .get('/api/exception_lists/items/_find') + .get('/api/exception_lists/_find') .set('kbn-xsrf', 'true') .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') diff --git a/x-pack/test/api_integration/services/security_solution_lists_api.gen.ts b/x-pack/test/api_integration/services/security_solution_lists_api.gen.ts index 4f201d868e92c..9800f0b802873 100644 --- a/x-pack/test/api_integration/services/security_solution_lists_api.gen.ts +++ b/x-pack/test/api_integration/services/security_solution_lists_api.gen.ts @@ -98,7 +98,7 @@ export function SecuritySolutionApiProvider({ getService }: FtrProviderContext) }, findListItems(props: FindListItemsProps) { return supertest - .get('/api/lists/_find') + .get('/api/lists/items/_find') .set('kbn-xsrf', 'true') .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') diff --git a/x-pack/test/cases_api_integration/common/plugins/cases/server/plugin.ts b/x-pack/test/cases_api_integration/common/plugins/cases/server/plugin.ts index 8d5ee1660d1fd..a609d014b1c5f 100644 --- a/x-pack/test/cases_api_integration/common/plugins/cases/server/plugin.ts +++ b/x-pack/test/cases_api_integration/common/plugins/cases/server/plugin.ts @@ -6,7 +6,7 @@ */ import { Plugin, CoreSetup, CoreStart, PluginInitializerContext, Logger } from '@kbn/core/server'; -import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { SpacesPluginStart } from '@kbn/spaces-plugin/server'; import { SecurityPluginStart } from '@kbn/security-plugin/server'; import type { CasesServerStart, CasesServerSetup } from '@kbn/cases-plugin/server'; diff --git a/x-pack/test/cases_api_integration/common/plugins/observability/server/plugin.ts b/x-pack/test/cases_api_integration/common/plugins/observability/server/plugin.ts index a338099a56b98..8887e0d52ca62 100644 --- a/x-pack/test/cases_api_integration/common/plugins/observability/server/plugin.ts +++ b/x-pack/test/cases_api_integration/common/plugins/observability/server/plugin.ts @@ -7,7 +7,7 @@ import { Plugin, CoreSetup } from '@kbn/core/server'; import { hiddenTypes as filesSavedObjectTypes } from '@kbn/files-plugin/server/saved_objects'; -import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { SpacesPluginStart } from '@kbn/spaces-plugin/server'; import { SecurityPluginStart } from '@kbn/security-plugin/server'; diff --git a/x-pack/test/cases_api_integration/common/plugins/security_solution/server/plugin.ts b/x-pack/test/cases_api_integration/common/plugins/security_solution/server/plugin.ts index 2fd5b5ced2b9b..4adf4d840e0e1 100644 --- a/x-pack/test/cases_api_integration/common/plugins/security_solution/server/plugin.ts +++ b/x-pack/test/cases_api_integration/common/plugins/security_solution/server/plugin.ts @@ -7,7 +7,7 @@ import { Plugin, CoreSetup } from '@kbn/core/server'; import { hiddenTypes as filesSavedObjectTypes } from '@kbn/files-plugin/server/saved_objects'; -import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { SpacesPluginStart } from '@kbn/spaces-plugin/server'; import { SecurityPluginStart } from '@kbn/security-plugin/server'; diff --git a/x-pack/test/cloud_security_posture_functional/page_objects/add_cis_integration_form_page.ts b/x-pack/test/cloud_security_posture_functional/page_objects/add_cis_integration_form_page.ts index 75ba76b067cc9..ba10dc2a7e4f6 100644 --- a/x-pack/test/cloud_security_posture_functional/page_objects/add_cis_integration_form_page.ts +++ b/x-pack/test/cloud_security_posture_functional/page_objects/add_cis_integration_form_page.ts @@ -175,12 +175,12 @@ export function AddCisIntegrationFormPageProvider({ await integrationList[0].click(); }; - const clickLaunchAndGetCurrentUrl = async (buttonId: string, tabNumber: number) => { + const clickLaunchAndGetCurrentUrl = async (buttonId: string) => { const button = await testSubjects.find(buttonId); await button.click(); - await browser.switchTab(tabNumber); - await new Promise((r) => setTimeout(r, 3000)); + await browser.switchTab(1); const currentUrl = await browser.getCurrentUrl(); + await browser.closeCurrentWindow(); await browser.switchTab(0); return currentUrl; }; diff --git a/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cnvm/cis_integration_cnvm.ts b/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cnvm/cis_integration_cnvm.ts index a91d35ea668be..66272995b0357 100644 --- a/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cnvm/cis_integration_cnvm.ts +++ b/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cnvm/cis_integration_cnvm.ts @@ -58,8 +58,7 @@ export default function (providerContext: FtrProviderContext) { expect( ( await cisIntegration.clickLaunchAndGetCurrentUrl( - 'confirmCloudFormationModalConfirmButton', - 1 + 'confirmCloudFormationModalConfirmButton' ) ).includes('console.aws.amazon.com%2Fcloudformation') ).to.be(true); diff --git a/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cspm/cis_integration_aws.ts b/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cspm/cis_integration_aws.ts index 10c2f0560237c..a8e0e9eee55af 100644 --- a/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cspm/cis_integration_aws.ts +++ b/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cspm/cis_integration_aws.ts @@ -77,8 +77,7 @@ export default function (providerContext: FtrProviderContext) { expect( ( await cisIntegration.clickLaunchAndGetCurrentUrl( - 'confirmCloudFormationModalConfirmButton', - 2 + 'confirmCloudFormationModalConfirmButton' ) ).includes('console.aws.amazon.com%2Fcloudformation') ).to.be(true); diff --git a/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cspm/cis_integration_gcp.ts b/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cspm/cis_integration_gcp.ts index e8d1dcda1f430..66bd58ea4967e 100644 --- a/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cspm/cis_integration_gcp.ts +++ b/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cspm/cis_integration_gcp.ts @@ -24,8 +24,7 @@ export default function (providerContext: FtrProviderContext) { const { getPageObjects } = providerContext; const pageObjects = getPageObjects(['cloudPostureDashboard', 'cisAddIntegration', 'header']); - // Failing: See https://github.com/elastic/kibana/issues/186440 - describe.skip('Test adding Cloud Security Posture Integrations CSPM GCP', function () { + describe('Test adding Cloud Security Posture Integrations CSPM GCP', function () { this.tags(['cloud_security_posture_cis_integration_cspm_gcp']); let cisIntegrationGcp: typeof pageObjects.cisAddIntegration.cisGcp; let cisIntegration: typeof pageObjects.cisAddIntegration; @@ -125,8 +124,7 @@ export default function (providerContext: FtrProviderContext) { expect( ( await cisIntegration.clickLaunchAndGetCurrentUrl( - 'confirmGoogleCloudShellModalConfirmButton', - 3 + 'confirmGoogleCloudShellModalConfirmButton' ) ).includes('shell.cloud.google.com%2Fcloudshell') ).to.be(true); @@ -251,10 +249,11 @@ export default function (providerContext: FtrProviderContext) { await cisIntegration.fillInTextField(CREDENTIALS_JSON_TEST_ID, credentialJsonName); await cisIntegration.clickSaveIntegrationButton(); await pageObjects.header.waitUntilLoadingHasFinished(); - await cisIntegration.navigateToIntegrationCspList(); + await cisIntegration.clickFirstElementOnIntegrationTable(); expect( - (await cisIntegration.getFieldValueInEditPage(CREDENTIALS_JSON_TEST_ID)) === - credentialJsonName + (await cisIntegration.getSecretComponentReplaceButton( + 'button-replace-credentials-json' + )) !== undefined ).to.be(true); }); it('Users are able to add CIS_GCP Integration with Manual settings using Credentials JSON', async () => { diff --git a/x-pack/test/fleet_api_integration/apis/integrations/inputs_with_standalone_docker_agent.ts b/x-pack/test/fleet_api_integration/apis/integrations/inputs_with_standalone_docker_agent.ts index a79dde78d7e88..ca1d8c0c3f312 100644 --- a/x-pack/test/fleet_api_integration/apis/integrations/inputs_with_standalone_docker_agent.ts +++ b/x-pack/test/fleet_api_integration/apis/integrations/inputs_with_standalone_docker_agent.ts @@ -25,9 +25,7 @@ export default function (providerContext: FtrProviderContext) { const config = getService('config'); const log = getService('log'); - // Failing: See https://github.com/elastic/kibana/issues/184681 - // Failing: See https://github.com/elastic/kibana/issues/184681 - describe.skip('inputs_with_standalone_docker_agent', () => { + describe('inputs_with_standalone_docker_agent', () => { skipIfNoDockerRegistry(providerContext); let apiKey: string; let agent: AgentProcess; diff --git a/x-pack/test/functional/apps/dataset_quality/home.ts b/x-pack/test/functional/apps/dataset_quality/home.ts index e08a06620e605..9b9f601edd138 100644 --- a/x-pack/test/functional/apps/dataset_quality/home.ts +++ b/x-pack/test/functional/apps/dataset_quality/home.ts @@ -44,7 +44,6 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid }); it('dataset quality table exists', async () => { - await PageObjects.datasetQuality.navigateTo(); await testSubjects.existOrFail( PageObjects.datasetQuality.testSubjectSelectors.datasetQualityTable ); diff --git a/x-pack/test/functional/apps/lens/group6/lens_reporting.ts b/x-pack/test/functional/apps/lens/group6/lens_reporting.ts index 4d882f59d13bc..5b9063cf6cf54 100644 --- a/x-pack/test/functional/apps/lens/group6/lens_reporting.ts +++ b/x-pack/test/functional/apps/lens/group6/lens_reporting.ts @@ -96,7 +96,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { // open the share menu and check that reporting is disabled await PageObjects.lens.clickShareModal(); - expect(await PageObjects.lens.isShareActionEnabled(`export`)); + expect(await testSubjects.exists('export')).to.be(false); await PageObjects.lens.closeShareModal(); }); diff --git a/x-pack/test/functional/apps/ml/anomaly_detection_integrations/single_metric_viewer_dashboard_embeddables.ts b/x-pack/test/functional/apps/ml/anomaly_detection_integrations/single_metric_viewer_dashboard_embeddables.ts index 3670b31fe609a..3d3ea27add87f 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection_integrations/single_metric_viewer_dashboard_embeddables.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection_integrations/single_metric_viewer_dashboard_embeddables.ts @@ -45,7 +45,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); for (const testData of testDataList) { - describe(testData.suiteSuffix, function () { + // FLAKY: https://github.com/elastic/kibana/issues/188493 + describe.skip(testData.suiteSuffix, function () { before(async () => { await ml.api.createAndRunAnomalyDetectionLookbackJob( testData.jobConfig, diff --git a/x-pack/test/functional/apps/observability_logs_explorer/columns_selection.ts b/x-pack/test/functional/apps/observability_logs_explorer/columns_selection.ts index 2ce47eb927d8c..2ea761cb9913c 100644 --- a/x-pack/test/functional/apps/observability_logs_explorer/columns_selection.ts +++ b/x-pack/test/functional/apps/observability_logs_explorer/columns_selection.ts @@ -169,9 +169,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should render a popover with cell actions when a chip on content column is clicked', async () => { await retry.tryForTime(TEST_TIMEOUT, async () => { const cellElement = await dataGrid.getCellElement(0, 4); - const logLevelChip = await cellElement.findByTestSubject( - 'dataTablePopoverChip_log.level' - ); + const logLevelChip = await cellElement.findByTestSubject('*logLevelBadge-'); await logLevelChip.click(); // Check Filter In button is present await testSubjects.existOrFail('dataTableCellAction_addToFilterAction_log.level'); @@ -185,9 +183,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should render the table filtered where log.level value is info when filter in action is clicked', async () => { await retry.tryForTime(TEST_TIMEOUT, async () => { const cellElement = await dataGrid.getCellElement(0, 4); - const logLevelChip = await cellElement.findByTestSubject( - 'dataTablePopoverChip_log.level' - ); + const logLevelChip = await cellElement.findByTestSubject('*logLevelBadge-'); await logLevelChip.click(); // Find Filter In button @@ -196,7 +192,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); await filterInButton.click(); - const rowWithLogLevelInfo = await testSubjects.findAll('dataTablePopoverChip_log.level'); + const rowWithLogLevelInfo = await testSubjects.findAll('*logLevelBadge-'); expect(rowWithLogLevelInfo.length).to.be(4); }); @@ -205,9 +201,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should render the table filtered where log.level value is not info when filter out action is clicked', async () => { await retry.tryForTime(TEST_TIMEOUT, async () => { const cellElement = await dataGrid.getCellElement(0, 4); - const logLevelChip = await cellElement.findByTestSubject( - 'dataTablePopoverChip_log.level' - ); + const logLevelChip = await cellElement.findByTestSubject('*logLevelBadge-'); await logLevelChip.click(); // Find Filter Out button @@ -216,7 +210,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); await filterOutButton.click(); - await testSubjects.missingOrFail('dataTablePopoverChip_log.level'); + await testSubjects.missingOrFail('*logLevelBadge-'); }); }); diff --git a/x-pack/test/functional_execution_context/plugins/alerts/server/plugin.ts b/x-pack/test/functional_execution_context/plugins/alerts/server/plugin.ts index b05a650d21b20..7f78f95913cf7 100644 --- a/x-pack/test/functional_execution_context/plugins/alerts/server/plugin.ts +++ b/x-pack/test/functional_execution_context/plugins/alerts/server/plugin.ts @@ -9,7 +9,7 @@ import apmAgent from 'elastic-apm-node'; import type { Plugin, CoreSetup } from '@kbn/core/server'; import { PluginSetupContract as AlertingPluginSetup } from '@kbn/alerting-plugin/server/plugin'; import { EncryptedSavedObjectsPluginStart } from '@kbn/encrypted-saved-objects-plugin/server'; -import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { SpacesPluginStart } from '@kbn/spaces-plugin/server'; import { SecurityPluginStart } from '@kbn/security-plugin/server'; diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/stack_alerts_page.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/stack_alerts_page.ts index 0c3d801e29371..5ab4e23cdc464 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/stack_alerts_page.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/stack_alerts_page.ts @@ -90,8 +90,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); }); - // FLAKY: https://github.com/elastic/kibana/issues/187667 - describe.skip('Loads the page', () => { + describe('Loads the page', () => { beforeEach(async () => { await security.testUser.restoreDefaults(); await pageObjects.common.navigateToUrl( @@ -112,62 +111,92 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { it('Shows all solution quick filters', async () => { await pageObjects.triggersActionsUI.clickAlertsPageShowQueryMenuButton(); - const quickFilters = await pageObjects.triggersActionsUI.getAlertsPageQuickFilters(); - const solutionFilters = getSolutionNamesFromFilters(quickFilters); - expect(FILTERABLE_SOLUTIONS.every((s) => solutionFilters.includes(s))); + + await retry.try(async () => { + const quickFilters = await pageObjects.triggersActionsUI.getAlertsPageQuickFilters(); + const solutionFilters = getSolutionNamesFromFilters(quickFilters); + expect(FILTERABLE_SOLUTIONS.every((s) => solutionFilters.includes(s))); + }); }); it('Applies the correct quick filter', async () => { await pageObjects.triggersActionsUI.clickAlertsPageShowQueryMenuButton(); - const quickFilters = await pageObjects.triggersActionsUI.getAlertsPageQuickFilters(); - const firstSolutionFilter = quickFilters - .filter((_: number, f: any) => f.attribs['data-test-subj'].endsWith('rule types')) - .first(); - expect(firstSolutionFilter).to.not.be(null); + + let firstSolutionFilter: any; + await retry.try(async () => { + const quickFilters = await pageObjects.triggersActionsUI.getAlertsPageQuickFilters(); + firstSolutionFilter = quickFilters + .filter((_: number, f: any) => f.attribs['data-test-subj'].endsWith('rule types')) + .first(); + expect(firstSolutionFilter).to.not.be(null); + }); + await testSubjects.click(firstSolutionFilter!.attr('data-test-subj')); - const appliedFilters = await pageObjects.triggersActionsUI.getAlertsPageAppliedFilters(); - expect(appliedFilters).to.have.length(1); - expect(await appliedFilters[0].getVisibleText()).to.contain(firstSolutionFilter!.text()); + + await retry.try(async () => { + const appliedFilters = await pageObjects.triggersActionsUI.getAlertsPageAppliedFilters(); + expect(appliedFilters).to.have.length(1); + expect(await appliedFilters[0].getVisibleText()).to.contain(firstSolutionFilter!.text()); + }); }); it('Disables all other solution filters when SIEM is applied', async () => { await pageObjects.triggersActionsUI.clickAlertsPageShowQueryMenuButton(); - let quickFilters = await pageObjects.triggersActionsUI.getAlertsPageQuickFilters(); - const filter = quickFilters - .filter((_: number, f: any) => - f.attribs['data-test-subj'].includes('Security rule types') - ) - .first(); + + let quickFilters: any; + let filter: any; + await retry.try(async () => { + quickFilters = await pageObjects.triggersActionsUI.getAlertsPageQuickFilters(); + filter = quickFilters + .filter((_: number, f: any) => + f.attribs['data-test-subj'].includes('Security rule types') + ) + .first(); + expect(filter).to.not.be(null); + }); await testSubjects.click(filter!.attr('data-test-subj')); - quickFilters = await pageObjects.triggersActionsUI.getAlertsPageQuickFilters(); - const nonSiemSolutionFilters = quickFilters.filter((_: number, f: any) => { - const testSubj = f.attribs['data-test-subj']; - return ( - testSubj.endsWith('rule types') && - !testSubj.includes('Security') && - !('disabled' in f.attribs) - ); + + await retry.try(async () => { + quickFilters = await pageObjects.triggersActionsUI.getAlertsPageQuickFilters(); + const nonSiemSolutionFilters = quickFilters.filter((_: number, f: any) => { + const testSubj = f.attribs['data-test-subj']; + return ( + testSubj.endsWith('rule types') && + !testSubj.includes('Security') && + !('disabled' in f.attribs) + ); + }); + expect(nonSiemSolutionFilters).to.have.length(0); }); - expect(nonSiemSolutionFilters).to.have.length(0); }); it('Disables the SIEM solution filter when any other is applied', async () => { await pageObjects.triggersActionsUI.clickAlertsPageShowQueryMenuButton(); - let quickFilters = await pageObjects.triggersActionsUI.getAlertsPageQuickFilters(); - const filter = quickFilters - .filter((_: number, f: any) => { - const testSubj = f.attribs['data-test-subj']; - return testSubj.includes('rule types') && !testSubj.includes('Security'); - }) - .first(); + + let quickFilters: any; + let filter: any; + await retry.try(async () => { + quickFilters = await pageObjects.triggersActionsUI.getAlertsPageQuickFilters(); + filter = quickFilters + .filter((_: number, f: any) => { + const testSubj = f.attribs['data-test-subj']; + return testSubj.includes('rule types') && !testSubj.includes('Security'); + }) + .first(); + expect(filter).to.not.be(null); + }); + await testSubjects.click(filter!.attr('data-test-subj')); - quickFilters = await pageObjects.triggersActionsUI.getAlertsPageQuickFilters(); - const siemSolutionFilter = quickFilters - .filter((_: number, f: any) => - f.attribs['data-test-subj'].includes('Security rule types') - ) - .first(); - expect(siemSolutionFilter.attr('disabled')).to.not.be(null); + + await retry.try(async () => { + quickFilters = await pageObjects.triggersActionsUI.getAlertsPageQuickFilters(); + const siemSolutionFilter = quickFilters + .filter((_: number, f: any) => + f.attribs['data-test-subj'].includes('Security rule types') + ) + .first(); + expect(siemSolutionFilter.attr('disabled')).to.not.be(null); + }); }); }); }); diff --git a/x-pack/test/functional_with_es_ssl/plugins/alerts/server/plugin.ts b/x-pack/test/functional_with_es_ssl/plugins/alerts/server/plugin.ts index c1e968cd41029..985687d99798e 100644 --- a/x-pack/test/functional_with_es_ssl/plugins/alerts/server/plugin.ts +++ b/x-pack/test/functional_with_es_ssl/plugins/alerts/server/plugin.ts @@ -11,7 +11,7 @@ import { RuleType, RuleTypeParams, } from '@kbn/alerting-plugin/server'; -import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; // this plugin's dependendencies export interface AlertingExampleDeps { diff --git a/x-pack/test/plugin_api_integration/test_suites/task_manager/check_registered_task_types.ts b/x-pack/test/plugin_api_integration/test_suites/task_manager/check_registered_task_types.ts index 26f4df962231f..011da0ff699bd 100644 --- a/x-pack/test/plugin_api_integration/test_suites/task_manager/check_registered_task_types.ts +++ b/x-pack/test/plugin_api_integration/test_suites/task_manager/check_registered_task_types.ts @@ -158,6 +158,7 @@ export default function ({ getService }: FtrProviderContext) { 'security:telemetry-prebuilt-rule-alerts', 'security:telemetry-timelines', 'session_cleanup', + 'task_manager:delete_inactive_background_task_nodes', ]); }); }); diff --git a/x-pack/test/plugin_api_integration/test_suites/task_manager/index.ts b/x-pack/test/plugin_api_integration/test_suites/task_manager/index.ts index 14b720bc68a55..3b943347cea7e 100644 --- a/x-pack/test/plugin_api_integration/test_suites/task_manager/index.ts +++ b/x-pack/test/plugin_api_integration/test_suites/task_manager/index.ts @@ -17,6 +17,7 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./task_management_scheduled_at')); loadTestFile(require.resolve('./task_management_removed_types')); loadTestFile(require.resolve('./check_registered_task_types')); + loadTestFile(require.resolve('./kibana_discovery_service')); loadTestFile(require.resolve('./migrations')); }); diff --git a/x-pack/test/plugin_api_integration/test_suites/task_manager/kibana_discovery_service.ts b/x-pack/test/plugin_api_integration/test_suites/task_manager/kibana_discovery_service.ts new file mode 100644 index 0000000000000..f944f64147710 --- /dev/null +++ b/x-pack/test/plugin_api_integration/test_suites/task_manager/kibana_discovery_service.ts @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../common/ftr_provider_context'; + +export default function createTaskManagementScheduledAtTests({ getService }: FtrProviderContext) { + const es = getService('es'); + const retry = getService('retry'); + + const getBackgroundTaskNodes = async () => + es.search( + { + index: '.kibana_task_manager', + size: 100, + body: { + query: { + term: { + type: 'background-task-node', + }, + }, + }, + }, + { + meta: true, + } + ); + + describe('kibana discovery service', () => { + it('creates and updates the background-task-node SO', async () => { + let lastSeen: number; + await retry.try(async () => { + const response = await getBackgroundTaskNodes(); + expect(response.statusCode).to.eql(200); + // @ts-expect-error doesnt handle total: number + expect(response.body?.hits?.total?.value).to.eql(1); + + const backgroundTaskNode = (response.body?.hits?.hits?.[0]._source as any)[ + 'background-task-node' + ]; + + expect(backgroundTaskNode.id).to.be('5b2de169-2785-441b-ae8c-186a1936b17d'); + + lastSeen = new Date(backgroundTaskNode.last_seen).getTime(); + }); + + // waits for 10s and updates the value of last_seen + await retry.try(async () => { + const response = await getBackgroundTaskNodes(); + expect(response.statusCode).to.eql(200); + const backgroundTaskNode = (response.body?.hits?.hits?.[0]._source as any)[ + 'background-task-node' + ]; + const updatedLastSeen = new Date(backgroundTaskNode.last_seen).getTime(); + expect(updatedLastSeen - lastSeen).to.greaterThan(10000 - 1); // 10s interval + }); + }); + }); +} diff --git a/x-pack/test/screenshot_creation/apps/response_ops_docs/observability_cases/custom_fields.ts b/x-pack/test/screenshot_creation/apps/response_ops_docs/observability_cases/custom_fields.ts index 0359ad270654a..ca49737909fe9 100644 --- a/x-pack/test/screenshot_creation/apps/response_ops_docs/observability_cases/custom_fields.ts +++ b/x-pack/test/screenshot_creation/apps/response_ops_docs/observability_cases/custom_fields.ts @@ -28,7 +28,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { 700 ); await testSubjects.setValue('custom-field-label-input', 'my-field'); - await testSubjects.click('custom-field-flyout-save'); + await testSubjects.click('common-flyout-save'); await commonScreenshots.takeScreenshot( 'cases-custom-field-settings', screenshotDirectories, diff --git a/x-pack/test/screenshot_creation/apps/response_ops_docs/security_cases/custom_fields.ts b/x-pack/test/screenshot_creation/apps/response_ops_docs/security_cases/custom_fields.ts index 6320f7a09d958..c3926cd903519 100644 --- a/x-pack/test/screenshot_creation/apps/response_ops_docs/security_cases/custom_fields.ts +++ b/x-pack/test/screenshot_creation/apps/response_ops_docs/security_cases/custom_fields.ts @@ -19,6 +19,14 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await pageObjects.header.waitUntilLoadingHasFinished(); await testSubjects.click('configure-case-button'); await commonScreenshots.takeScreenshot('cases-settings', screenshotDirectories); + await testSubjects.click('add-template'); + await commonScreenshots.takeScreenshot( + 'cases-add-template', + screenshotDirectories, + 1400, + 1000 + ); + await testSubjects.click('common-flyout-cancel'); await testSubjects.click('add-custom-field'); await commonScreenshots.takeScreenshot( 'cases-add-custom-field', @@ -27,7 +35,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 700 ); await testSubjects.setValue('custom-field-label-input', 'my-field'); - await testSubjects.click('custom-field-flyout-save'); + await testSubjects.click('common-flyout-save'); await commonScreenshots.takeScreenshot( 'cases-custom-field-settings', screenshotDirectories, diff --git a/x-pack/test/screenshot_creation/apps/response_ops_docs/stack_cases/external_connections.ts b/x-pack/test/screenshot_creation/apps/response_ops_docs/stack_cases/external_connections.ts deleted file mode 100644 index cb880f79d02ce..0000000000000 --- a/x-pack/test/screenshot_creation/apps/response_ops_docs/stack_cases/external_connections.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 { FtrProviderContext } from '../../../ftr_provider_context'; - -export default function ({ getService }: FtrProviderContext) { - const cases = getService('cases'); - const commonScreenshots = getService('commonScreenshots'); - - const screenshotDirectories = ['response_ops_docs', 'stack_cases']; - - describe('edit external connections', function () { - it('cases configure screenshot', async () => { - await cases.navigation.navigateToApp(); - await cases.navigation.navigateToConfigurationPage(); - await commonScreenshots.takeScreenshot('cases-settings', screenshotDirectories, 1400, 1024); - }); - }); -} diff --git a/x-pack/test/screenshot_creation/apps/response_ops_docs/stack_cases/index.ts b/x-pack/test/screenshot_creation/apps/response_ops_docs/stack_cases/index.ts index 97d48aa70df4d..e9ebb8e9b2bcf 100644 --- a/x-pack/test/screenshot_creation/apps/response_ops_docs/stack_cases/index.ts +++ b/x-pack/test/screenshot_creation/apps/response_ops_docs/stack_cases/index.ts @@ -47,8 +47,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { }); loadTestFile(require.resolve('./list_view')); + loadTestFile(require.resolve('./settings')); loadTestFile(require.resolve('./details_view')); - loadTestFile(require.resolve('./external_connections')); - loadTestFile(require.resolve('./custom_fields')); }); } diff --git a/x-pack/test/screenshot_creation/apps/response_ops_docs/stack_cases/custom_fields.ts b/x-pack/test/screenshot_creation/apps/response_ops_docs/stack_cases/settings.ts similarity index 68% rename from x-pack/test/screenshot_creation/apps/response_ops_docs/stack_cases/custom_fields.ts rename to x-pack/test/screenshot_creation/apps/response_ops_docs/stack_cases/settings.ts index 774bc6fd5c06a..b3526a512e913 100644 --- a/x-pack/test/screenshot_creation/apps/response_ops_docs/stack_cases/custom_fields.ts +++ b/x-pack/test/screenshot_creation/apps/response_ops_docs/stack_cases/settings.ts @@ -9,41 +9,32 @@ import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getPageObject, getService }: FtrProviderContext) { const cases = getService('cases'); const commonScreenshots = getService('commonScreenshots'); - const find = getService('find'); - const header = getPageObject('header'); const testSubjects = getService('testSubjects'); const screenshotDirectories = ['response_ops_docs', 'stack_cases']; - describe('add custom fields', function () { + describe('case settings', function () { it('case settings screenshot', async () => { await cases.navigation.navigateToApp(); await cases.navigation.navigateToConfigurationPage(); - await testSubjects.click('add-custom-field'); + await commonScreenshots.takeScreenshot('cases-settings', screenshotDirectories, 1400, 1024); + await testSubjects.click('add-template'); await commonScreenshots.takeScreenshot( - 'cases-custom-fields-add', + 'cases-templates-add', screenshotDirectories, 1400, - 700 + 1000 ); - await testSubjects.setValue('custom-field-label-input', 'my-field'); - await testSubjects.click('custom-field-flyout-save'); - await commonScreenshots.takeScreenshot( - 'cases-custom-fields-view', - screenshotDirectories, - 1400, - 1024 - ); - await cases.navigation.navigateToApp(); - await cases.casesTable.waitForCasesToBeListed(); - await cases.casesTable.goToFirstListedCase(); - await header.waitUntilLoadingHasFinished(); - await find.byCssSelector('[data-test-subj="no-custom-field-value"]'); + await testSubjects.click('common-flyout-cancel'); + await testSubjects.click('add-custom-field'); await commonScreenshots.takeScreenshot( - 'cases-custom-fields', + 'cases-custom-fields-add', screenshotDirectories, 1400, - 1400 + 700 ); + await testSubjects.setValue('custom-field-label-input', 'my-field'); + await testSubjects.click('common-flyout-save'); + await commonScreenshots.takeScreenshot('cases-settings', screenshotDirectories, 1400, 1024); await cases.navigation.navigateToApp(); await testSubjects.click('createNewCaseBtn'); await commonScreenshots.takeScreenshot('cases-create', screenshotDirectories, 1400, 1900); diff --git a/x-pack/test/security_api_integration/plugins/user_profiles_consumer/server/index.ts b/x-pack/test/security_api_integration/plugins/user_profiles_consumer/server/index.ts index 7cd8187558a88..3922cc233cca9 100644 --- a/x-pack/test/security_api_integration/plugins/user_profiles_consumer/server/index.ts +++ b/x-pack/test/security_api_integration/plugins/user_profiles_consumer/server/index.ts @@ -6,10 +6,7 @@ */ import type { PluginInitializer, Plugin, CoreSetup } from '@kbn/core/server'; -import { - PluginSetupContract as FeaturesPluginSetup, - PluginStartContract as FeaturesPluginStart, -} from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup, FeaturesPluginStart } from '@kbn/features-plugin/server'; import { SecurityPluginSetup, SecurityPluginStart } from '@kbn/security-plugin/server'; import { SpacesPluginSetup, SpacesPluginStart } from '@kbn/spaces-plugin/server'; import { initRoutes } from './init_routes'; diff --git a/x-pack/test/security_solution_api_integration/package.json b/x-pack/test/security_solution_api_integration/package.json index 4ec0553f981c8..f750078df62ce 100644 --- a/x-pack/test/security_solution_api_integration/package.json +++ b/x-pack/test/security_solution_api_integration/package.json @@ -45,13 +45,6 @@ "intialize-server:explore": "node scripts/index.js server explore trial_license_complete_tier", "run-tests:explore": "node scripts/index.js runner explore trial_license_complete_tier", - "genai:server:serverless": "npm run initialize-server:genai:trial_complete invoke_ai serverless", - "genai:runner:serverless": "npm run run-tests:genai:trial_complete invoke_ai serverless serverlessEnv", - "genai:qa:serverless": "npm run run-tests:genai:trial_complete invoke_ai serverless qaPeriodicEnv", - "genai:qa:serverless:release": "npm run run-tests:genai:trial_complete invoke_ai serverless qaEnv", - "genai:server:ess": "npm run initialize-server:genai:trial_complete invoke_ai ess", - "genai:runner:ess": "npm run run-tests:genai:trial_complete invoke_ai ess essEnv", - "nlp_cleanup_task:complete:server:serverless": "npm run initialize-server:genai:trial_complete nlp_cleanup_task serverless", "nlp_cleanup_task:complete:runner:serverless": "npm run run-tests:genai:trial_complete nlp_cleanup_task serverless serverlessEnv", "nlp_cleanup_task:complete:qa:serverless": "npm run run-tests:genai:trial_complete nlp_cleanup_task serverless qaPeriodicEnv", diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/actions/trial_license_complete_tier/check_privileges.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/actions/trial_license_complete_tier/check_privileges.ts index 966f92bbc4672..c45bf13c66aad 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/actions/trial_license_complete_tier/check_privileges.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/actions/trial_license_complete_tier/check_privileges.ts @@ -83,7 +83,7 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); // TODO: https://github.com/elastic/kibana/pull/121644 clean up, make type-safe - expect(body?.execution_summary?.last_execution.message).to.eql( + expect(body?.execution_summary?.last_execution.message).to.contain( `This rule may not have the required read privileges to the following index patterns: ["${index[0]}"]` ); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/trial_license_complete_tier/execution_logic/eql.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/trial_license_complete_tier/execution_logic/eql.ts index 24b336587bae2..ad43e7e9aa77a 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/trial_license_complete_tier/execution_logic/eql.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/rule_execution_logic/trial_license_complete_tier/execution_logic/eql.ts @@ -896,8 +896,8 @@ export default ({ getService }: FtrProviderContext) => { logs: [_log], } = await previewRule({ supertest, rule }); - expect(_log.errors).to.contain( - 'An error occurred during rule execution: message: "verification_exception\n\tRoot causes:\n\t\tverification_exception: Found 1 problem\nline -1:-1: Unknown column [@timestamp]"' + expect(_log.errors[0]).to.contain( + 'verification_exception\n\tRoot causes:\n\t\tverification_exception: Found 1 problem\nline -1:-1: Unknown column [@timestamp]' ); const previewAlerts = await getPreviewAlerts({ es, previewId }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/genai/invoke_ai/trial_license_complete_tier/basic.ts b/x-pack/test/security_solution_api_integration/test_suites/genai/invoke_ai/trial_license_complete_tier/basic.ts deleted file mode 100644 index 2be43b9188044..0000000000000 --- a/x-pack/test/security_solution_api_integration/test_suites/genai/invoke_ai/trial_license_complete_tier/basic.ts +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; - -import { BedrockSimulator } from '@kbn/actions-simulators-plugin/server/bedrock_simulation'; -import { OpenAISimulator } from '@kbn/actions-simulators-plugin/server/openai_simulation'; -import { FtrProviderContext } from '../../../../ftr_provider_context'; -import { postActionsClientExecute } from '../utils/post_actions_client_execute'; -import { ObjectRemover } from '../utils/object_remover'; -import { createConnector } from '../utils/create_connector'; - -const mockRequest = { - message: 'Do you know my name?', - subAction: 'invokeAI', - actionTypeId: '.bedrock', - isEnabledKnowledgeBase: false, - isEnabledRAGAlerts: false, - replacements: {}, -}; - -export default ({ getService }: FtrProviderContext) => { - const supertest = getService('supertest'); - const objectRemover = new ObjectRemover(supertest); - const configService = getService('config'); - - // @skipInServerlessMKI tag because the simulators do not work in the QA env - describe('@ess @serverless @skipInServerlessMKI Basic Security AI Assistant Invoke AI [non-streaming, non-LangChain]', async () => { - after(() => { - objectRemover.removeAll(); - }); - - describe('With Bedrock connector', () => { - const simulator = new BedrockSimulator({ - proxy: { - config: configService.get('kbnTestServer.serverArgs'), - }, - }); - let apiUrl: string; - let bedrockActionId: string; - - before(async () => { - apiUrl = await simulator.start(); - bedrockActionId = await createConnector(supertest, objectRemover, apiUrl, 'bedrock'); - }); - - after(() => { - simulator.close(); - }); - it('should execute a chat completion', async () => { - const response = await postActionsClientExecute(bedrockActionId, mockRequest, supertest); - - const expected = { - connector_id: bedrockActionId, - data: 'Hello there! How may I assist you today?', - status: 'ok', - }; - - expect(response.body).to.eql(expected); - }); - }); - - describe('With OpenAI connector', () => { - const simulator = new OpenAISimulator({ - returnError: false, - proxy: { - config: configService.get('kbnTestServer.serverArgs'), - }, - }); - let apiUrl: string; - let openaiActionId: string; - - before(async () => { - apiUrl = await simulator.start(); - openaiActionId = await createConnector(supertest, objectRemover, apiUrl, 'openai'); - }); - - after(() => { - simulator.close(); - }); - it('should execute a chat completion', async () => { - const response = await postActionsClientExecute( - openaiActionId, - { ...mockRequest, actionTypeId: '.gen-ai' }, - supertest - ); - - const expected = { - connector_id: openaiActionId, - data: 'Hello there! How may I assist you today?', - status: 'ok', - }; - - expect(response.body).to.eql(expected); - }); - }); - }); -}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/genai/invoke_ai/trial_license_complete_tier/configs/ess.config.ts b/x-pack/test/security_solution_api_integration/test_suites/genai/invoke_ai/trial_license_complete_tier/configs/ess.config.ts deleted file mode 100644 index 2674d0fe84764..0000000000000 --- a/x-pack/test/security_solution_api_integration/test_suites/genai/invoke_ai/trial_license_complete_tier/configs/ess.config.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FtrConfigProviderContext } from '@kbn/test'; -import getPort from 'get-port'; - -export default async function ({ readConfigFile }: FtrConfigProviderContext) { - const functionalConfig = await readConfigFile( - require.resolve('../../../../../config/ess/config.base.trial') - ); - - const proxyPort = await getPort({ port: getPort.makeRange(6200, 6299) }); - - return { - ...functionalConfig.getAll(), - kbnTestServer: { - ...functionalConfig.get('kbnTestServer'), - serverArgs: [ - ...functionalConfig.get('kbnTestServer.serverArgs'), - // used for connector simulators - `--xpack.actions.proxyUrl=http://localhost:${proxyPort}`, - `--xpack.actions.enabledActionTypes=${JSON.stringify(['.bedrock', '.gen-ai', '.gemini'])}`, - ], - }, - testFiles: [require.resolve('..')], - junit: { - reportName: 'GenAI - Invoke AI Tests - ESS Env - Trial License', - }, - }; -} diff --git a/x-pack/test/security_solution_api_integration/test_suites/genai/invoke_ai/trial_license_complete_tier/configs/serverless.config.ts b/x-pack/test/security_solution_api_integration/test_suites/genai/invoke_ai/trial_license_complete_tier/configs/serverless.config.ts deleted file mode 100644 index d0666e224e4bf..0000000000000 --- a/x-pack/test/security_solution_api_integration/test_suites/genai/invoke_ai/trial_license_complete_tier/configs/serverless.config.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { createTestConfig } from '../../../../../config/serverless/config.base'; - -export default createTestConfig({ - kbnTestServerArgs: [ - // used for connector simulators - `--xpack.actions.proxyUrl=http://localhost:6200`, - ], - testFiles: [require.resolve('..')], - junit: { - reportName: 'GenAI - Invoke AI Tests - Serverless Env - Complete Tier', - }, -}); diff --git a/x-pack/test/security_solution_api_integration/test_suites/genai/invoke_ai/trial_license_complete_tier/index.ts b/x-pack/test/security_solution_api_integration/test_suites/genai/invoke_ai/trial_license_complete_tier/index.ts deleted file mode 100644 index e6ff5bbbfe667..0000000000000 --- a/x-pack/test/security_solution_api_integration/test_suites/genai/invoke_ai/trial_license_complete_tier/index.ts +++ /dev/null @@ -1,15 +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 { FtrProviderContext } from '../../../../ftr_provider_context'; - -export default function ({ loadTestFile }: FtrProviderContext) { - // this is the test suite for the inaptly named post_actions_connector_execute route - describe('GenAI - Invoke AI', function () { - loadTestFile(require.resolve('./basic')); - }); -} diff --git a/x-pack/test/security_solution_api_integration/test_suites/genai/invoke_ai/utils/create_connector.ts b/x-pack/test/security_solution_api_integration/test_suites/genai/invoke_ai/utils/create_connector.ts deleted file mode 100644 index 0c7823ef07885..0000000000000 --- a/x-pack/test/security_solution_api_integration/test_suites/genai/invoke_ai/utils/create_connector.ts +++ /dev/null @@ -1,73 +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 SuperTest from 'supertest'; -import { - ELASTIC_HTTP_VERSION_HEADER, - X_ELASTIC_INTERNAL_ORIGIN_REQUEST, -} from '@kbn/core-http-common'; -import { getUrlPrefix } from './space_test_utils'; -import { ObjectRemover } from './object_remover'; - -const connectorSetup = { - bedrock: { - connectorTypeId: '.bedrock', - name: 'A bedrock action', - secrets: { - accessKey: 'bedrockAccessKey', - secret: 'bedrockSecret', - }, - config: { - defaultModel: 'anthropic.claude-v2', - }, - }, - openai: { - connectorTypeId: '.gen-ai', - name: 'An openai action', - secrets: { - apiKey: 'genAiApiKey', - }, - config: { - apiProvider: 'OpenAI', - }, - }, -}; - -/** - * Creates a connector - * @param supertest The supertest agent. - * @param apiUrl The url of the api - * @param connectorType The type of connector to create - * @param spaceId The space id - */ -export const createConnector = async ( - supertest: SuperTest.Agent, - objectRemover: ObjectRemover, - apiUrl: string, - connectorType: 'bedrock' | 'openai', - spaceId?: string -) => { - const { connectorTypeId, config, name, secrets } = connectorSetup[connectorType]; - const result = await supertest - .post(`${getUrlPrefix(spaceId ?? 'default')}/api/actions/connector`) - .set('kbn-xsrf', 'foo') - .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') - .send({ - name, - connector_type_id: connectorTypeId, - config: { ...config, apiUrl }, - secrets, - }) - .expect(200); - - const { body } = result; - - objectRemover.add(spaceId ?? 'default', body.id, 'connector', 'actions'); - - return body.id; -}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/genai/invoke_ai/utils/object_remover.ts b/x-pack/test/security_solution_api_integration/test_suites/genai/invoke_ai/utils/object_remover.ts deleted file mode 100644 index 93eaa85e802fc..0000000000000 --- a/x-pack/test/security_solution_api_integration/test_suites/genai/invoke_ai/utils/object_remover.ts +++ /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 { - ELASTIC_HTTP_VERSION_HEADER, - X_ELASTIC_INTERNAL_ORIGIN_REQUEST, -} from '@kbn/core-http-common'; -import { getUrlPrefix } from './space_test_utils'; - -interface ObjectToRemove { - spaceId: string; - id: string; - type: string; - plugin: string; - isInternal?: boolean; -} - -export class ObjectRemover { - private readonly supertest: any; - private objectsToRemove: ObjectToRemove[] = []; - - constructor(supertest: any) { - this.supertest = supertest; - } - - add( - spaceId: ObjectToRemove['spaceId'], - id: ObjectToRemove['id'], - type: ObjectToRemove['type'], - plugin: ObjectToRemove['plugin'], - isInternal?: ObjectToRemove['isInternal'] - ) { - this.objectsToRemove.push({ spaceId, id, type, plugin, isInternal }); - } - - async removeAll() { - await Promise.all( - this.objectsToRemove.map(({ spaceId, id, type, plugin, isInternal }) => { - return this.supertest - .delete( - `${getUrlPrefix(spaceId)}/${isInternal ? 'internal' : 'api'}/${plugin}/${type}/${id}` - ) - .set('kbn-xsrf', 'foo') - .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') - .expect(plugin === 'saved_objects' ? 200 : 204); - }) - ); - this.objectsToRemove = []; - } -} diff --git a/x-pack/test/security_solution_api_integration/test_suites/genai/invoke_ai/utils/post_actions_client_execute.ts b/x-pack/test/security_solution_api_integration/test_suites/genai/invoke_ai/utils/post_actions_client_execute.ts deleted file mode 100644 index b5ed8c15b3fb2..0000000000000 --- a/x-pack/test/security_solution_api_integration/test_suites/genai/invoke_ai/utils/post_actions_client_execute.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type SuperTest from 'supertest'; -import { - ELASTIC_HTTP_VERSION_HEADER, - X_ELASTIC_INTERNAL_ORIGIN_REQUEST, -} from '@kbn/core-http-common'; -import { Response } from 'superagent'; - -/** - * Executes an invoke AI action - * @param connectorId The connector id - * @param args The arguments to pass to the action - * @param supertest The supertest agent - */ -export const postActionsClientExecute = async ( - connectorId: string, - args: any, - supertest: SuperTest.Agent -): Promise => { - const response = await supertest - .post(`/internal/elastic_assistant/actions/connector/${connectorId}/_execute`) - .set('kbn-xsrf', 'true') - .set(ELASTIC_HTTP_VERSION_HEADER, '1') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') - .send(args); - - return response; -}; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_entities_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_entities_tab.cy.ts index 552c99b6dedb2..3f86c2859751b 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_entities_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_entities_tab.cy.ts @@ -10,10 +10,26 @@ import { DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS, DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS_RIGHT_SECTION, DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS_TITLE, + DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS_LINK, DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS, DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS_RIGHT_SECTION, DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS_TITLE, + DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS_LINK, } from '../../../../screens/expandable_flyout/alert_details_left_panel_entities_tab'; +import { + HOST_PANEL_HEADER, + HOST_PREVIEW_PANEL_FOOTER, + OPEN_HOST_FLYOUT_LINK, +} from '../../../../screens/hosts/flyout_host_panel'; +import { + USER_PANEL_HEADER, + USER_PREVIEW_PANEL_FOOTER, + OPEN_USER_FLYOUT_LINK, +} from '../../../../screens/users/flyout_user_panel'; +import { + PREVIEW_SECTION, + PREVIEW_BANNER, +} from '../../../../screens/expandable_flyout/alert_details_preview_panel'; import { DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB } from '../../../../screens/expandable_flyout/alert_details_left_panel'; import { openEntitiesTab } from '../../../../tasks/expandable_flyout/alert_details_left_panel_entities_tab'; import { openInsightsTab } from '../../../../tasks/expandable_flyout/alert_details_left_panel'; @@ -52,6 +68,8 @@ describe( .should('have.text', 'Entities') .and('have.class', 'euiButtonGroupButton-isSelected'); + // github.com/elastic/security-team/issues/9933 + // Comment out when feature flag 'entityAlertPreviewEnabled' is enabled cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS_TITLE).should( 'contain.text', 'test' @@ -62,6 +80,8 @@ describe( ); cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS).should('exist'); + // github.com/elastic/security-team/issues/9933 + // Comment out when feature flag 'entityAlertPreviewEnabled' is enabled cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS_TITLE).should( 'contain.text', 'siem-kibana' @@ -72,5 +92,46 @@ describe( ); cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS).should('exist'); }); + + // github.com/elastic/security-team/issues/9933 + // Enable when feature flag 'entityAlertPreviewEnabled' is enabled + it.skip('should open host preview when click on host details title', () => { + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS_LINK).should( + 'contain.text', + 'siem-kibana' + ); + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS_LINK).click(); + + cy.get(PREVIEW_SECTION).should('exist'); + cy.get(PREVIEW_BANNER).should('have.text', 'Preview host details'); + cy.get(HOST_PANEL_HEADER).should('exist'); + cy.get(HOST_PREVIEW_PANEL_FOOTER).should('exist'); + + cy.log('click on footer link'); + + cy.get(OPEN_HOST_FLYOUT_LINK).click(); + cy.get(HOST_PANEL_HEADER).should('exist'); + cy.get(PREVIEW_SECTION).should('not.exist'); + cy.get(HOST_PREVIEW_PANEL_FOOTER).should('not.exist'); + }); + + // github.com/elastic/security-team/issues/9933 + // Enable when feature flag 'entityAlertPreviewEnabled' is enabled + it.skip('should open user preview when click on user details title', () => { + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS_LINK).should('contain.text', 'test'); + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS_LINK).click(); + + cy.get(PREVIEW_SECTION).should('exist'); + cy.get(PREVIEW_BANNER).should('have.text', 'Preview user details'); + cy.get(USER_PANEL_HEADER).should('exist'); + cy.get(USER_PREVIEW_PANEL_FOOTER).should('exist'); + + cy.log('click on footer link'); + + cy.get(OPEN_USER_FLYOUT_LINK).click(); + cy.get(USER_PANEL_HEADER).should('exist'); + cy.get(PREVIEW_SECTION).should('not.exist'); + cy.get(USER_PREVIEW_PANEL_FOOTER).should('not.exist'); + }); } ); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_prevalence_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_prevalence_tab.cy.ts index f3bed7fab6b81..813c4f2c1229a 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_prevalence_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_prevalence_tab.cy.ts @@ -19,7 +19,23 @@ import { DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_TABLE_HOST_PREVALENCE_CELL, DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_TABLE_USER_PREVALENCE_CELL, DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_DATE_PICKER, + DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_TABLE_HOST_CELL, + DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_TABLE_USER_CELL, } from '../../../../screens/expandable_flyout/alert_details_left_panel_prevalence_tab'; +import { + HOST_PANEL_HEADER, + HOST_PREVIEW_PANEL_FOOTER, + OPEN_HOST_FLYOUT_LINK, +} from '../../../../screens/hosts/flyout_host_panel'; +import { + USER_PANEL_HEADER, + USER_PREVIEW_PANEL_FOOTER, + OPEN_USER_FLYOUT_LINK, +} from '../../../../screens/users/flyout_user_panel'; +import { + PREVIEW_SECTION, + PREVIEW_BANNER, +} from '../../../../screens/expandable_flyout/alert_details_preview_panel'; import { deleteAlertsAndRules } from '../../../../tasks/api_calls/common'; import { login } from '../../../../tasks/login'; import { visit } from '../../../../tasks/navigation'; @@ -83,5 +99,41 @@ describe( 100 ); }); + + // github.com/elastic/security-team/issues/9933 + // Enable when feature flag 'entityAlertPreviewEnabled' is enabled + it.skip('should open host preview when click on host details title', () => { + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_TABLE_HOST_CELL).click(); + + cy.get(PREVIEW_SECTION).should('exist'); + cy.get(PREVIEW_BANNER).should('have.text', 'Preview host details'); + cy.get(HOST_PANEL_HEADER).should('exist'); + cy.get(HOST_PREVIEW_PANEL_FOOTER).should('exist'); + + cy.log('should open host flyout when click on footer link'); + + cy.get(OPEN_HOST_FLYOUT_LINK).click(); + cy.get(HOST_PANEL_HEADER).should('exist'); + cy.get(PREVIEW_SECTION).should('not.exist'); + cy.get(HOST_PREVIEW_PANEL_FOOTER).should('not.exist'); + }); + + // github.com/elastic/security-team/issues/9933 + // Enable when feature flag 'entityAlertPreviewEnabled' is enabled + it.skip('should open user preview when click on user details title', () => { + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_TABLE_USER_CELL).click(); + + cy.get(PREVIEW_SECTION).should('exist'); + cy.get(PREVIEW_BANNER).should('have.text', 'Preview user details'); + cy.get(USER_PANEL_HEADER).should('exist'); + cy.get(USER_PREVIEW_PANEL_FOOTER).should('exist'); + + cy.log('should open host flyout when click on footer link'); + + cy.get(OPEN_USER_FLYOUT_LINK).click(); + cy.get(USER_PANEL_HEADER).should('exist'); + cy.get(PREVIEW_SECTION).should('not.exist'); + cy.get(HOST_PREVIEW_PANEL_FOOTER).should('not.exist'); + }); } ); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_preview_panel.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_preview_panel.cy.ts new file mode 100644 index 0000000000000..c000b06ff1016 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_preview_panel.cy.ts @@ -0,0 +1,175 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { openInsightsTab } from '../../../../tasks/expandable_flyout/alert_details_left_panel'; +import { expandAlertAtIndexExpandableFlyout } from '../../../../tasks/expandable_flyout/common'; +import { deleteAlertsAndRules } from '../../../../tasks/api_calls/common'; +import { login } from '../../../../tasks/login'; +import { visit } from '../../../../tasks/navigation'; +import { createRule } from '../../../../tasks/api_calls/rules'; +import { getNewRule } from '../../../../objects/rule'; +import { ALERTS_URL } from '../../../../urls/navigation'; +import { waitForAlertsToPopulate } from '../../../../tasks/create_new_rule'; +import { + CORRELATIONS_ANCESTRY_SECTION_TABLE, + CORRELATIONS_SESSION_SECTION_TABLE, + CORRELATIONS_SOURCE_SECTION_TABLE, +} from '../../../../screens/expandable_flyout/alert_details_left_panel_correlations_tab'; +import { + openCorrelationsTab, + clickExpandFromRelatedBySession, + clickExpandFromRelatedByAncestry, + clickExpandFromRelatedBySource, +} from '../../../../tasks/expandable_flyout/alert_details_left_panel_correlations_tab'; +import { + closePreview, + goToPreviousPreview, + openNewFlyout, +} from '../../../../tasks/expandable_flyout/alert_details_preview_panel'; +import { + DOCUMENT_DETAILS_FLYOUT_HEADER_LINK_ICON, + DOCUMENT_DETAILS_FLYOUT_HEADER_TITLE, + DOCUMENT_DETAILS_FLYOUT_FOOTER, + DOCUMENT_DETAILS_FLYOUT_FOOTER_TAKE_ACTION_BUTTON, +} from '../../../../screens/expandable_flyout/alert_details_right_panel'; +import { + PREVIEW_SECTION, + PREVIEW_BANNER, + DOCUMENT_DETAILS_FLYOUT_PREVIEW_FOOTER, + DOCUMENT_DETAILS_FLYOUT_PREVIEW_FOOTER_LINK, + PREVIEW_BACK_BUTTON, + PREVIEW_CLOSE_BUTTON, +} from '../../../../screens/expandable_flyout/alert_details_preview_panel'; +import { + expandDocumentDetailsExpandableFlyoutLeftSection, + openJsonTab, + openTableTab, +} from '../../../../tasks/expandable_flyout/alert_details_right_panel'; + +// github.com/elastic/security-team/issues/9933 +// Enable when feature flag 'entityAlertPreviewEnabled' is enabled +describe.skip( + 'Opening alert previews from alert details flyout', + { tags: ['@ess', '@serverless'] }, + () => { + const rule = getNewRule(); + + beforeEach(() => { + deleteAlertsAndRules(); + login(); + createRule(rule); + visit(ALERTS_URL); + waitForAlertsToPopulate(); + expandAlertAtIndexExpandableFlyout(); + expandDocumentDetailsExpandableFlyoutLeftSection(); + openInsightsTab(); + openCorrelationsTab(); + }); + + it('should render alert preview', () => { + cy.log('related alerts by source'); + cy.get(CORRELATIONS_SOURCE_SECTION_TABLE).should('exist'); + clickExpandFromRelatedBySource(); + + cy.log('Verify preview section is visible'); + cy.get(PREVIEW_SECTION).should('exist'); + cy.get(PREVIEW_BANNER).should('have.text', 'Preview alert details'); + cy.get(PREVIEW_BACK_BUTTON).should('exist'); + cy.get(PREVIEW_CLOSE_BUTTON).should('exist'); + + cy.log('Verify title and main sections are rendered'); + cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_TITLE).eq(1).should('have.text', rule.name); + cy.get(DOCUMENT_DETAILS_FLYOUT_HEADER_LINK_ICON).should('exist'); + + cy.log('Verify the open full alert detail footer is visible on all tabs'); + + cy.get(DOCUMENT_DETAILS_FLYOUT_PREVIEW_FOOTER).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_PREVIEW_FOOTER_LINK).should('be.visible'); + + openTableTab(1); + cy.get(DOCUMENT_DETAILS_FLYOUT_PREVIEW_FOOTER).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_PREVIEW_FOOTER_LINK).should('be.visible'); + + openJsonTab(1); + cy.get(DOCUMENT_DETAILS_FLYOUT_PREVIEW_FOOTER).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_PREVIEW_FOOTER_LINK).should('be.visible'); + }); + + it('should close previews when close button is clicked', () => { + cy.log('open alert preview from related alerts by session'); + cy.get(CORRELATIONS_SESSION_SECTION_TABLE).should('exist'); + clickExpandFromRelatedBySession(); + + cy.log('Verify preview section is visible'); + + cy.get(PREVIEW_SECTION).should('exist'); + cy.get(DOCUMENT_DETAILS_FLYOUT_PREVIEW_FOOTER).should('be.visible'); + + // TO-DO: enable when we can have multiple alerts in correlations + // cy.log('open another alert '); + // clickExpandFromRelatedBySession(1); + + // cy.get(PREVIEW_SECTION).should('exist'); + // cy.get(DOCUMENT_DETAILS_FLYOUT_PREVIEW_FOOTER).should('be.visible'); + + cy.log('click close button'); + + closePreview(); + cy.get(PREVIEW_SECTION).should('not.exist'); + cy.get(DOCUMENT_DETAILS_FLYOUT_PREVIEW_FOOTER).should('not.exist'); + }); + + // TO-DO: enable when we can have multiple alerts in correlations + it('should go to previous previews when back button is clicked', () => { + cy.log('open alert preview from related alerts by session'); + cy.get(CORRELATIONS_SESSION_SECTION_TABLE).should('exist'); + clickExpandFromRelatedBySession(); + + cy.log('Verify preview section is visible'); + + cy.get(PREVIEW_SECTION).should('exist'); + cy.get(DOCUMENT_DETAILS_FLYOUT_PREVIEW_FOOTER).should('be.visible'); + + // TO-DO: enable when we can have multiple alerts in correlations + // cy.log('open another alert '); + // clickExpandFromRelatedBySession(1); + + // cy.get(PREVIEW_SECTION).should('exist'); + // cy.get(DOCUMENT_DETAILS_FLYOUT_PREVIEW_FOOTER).should('be.visible'); + + // cy.log('click back button once'); + + // goToPreviousPreview(); + // cy.get(PREVIEW_SECTION).should('exist'); + // cy.get(DOCUMENT_DETAILS_FLYOUT_PREVIEW_FOOTER).should('be.visible'); + + cy.log('click back button again'); + goToPreviousPreview(); + cy.get(PREVIEW_SECTION).should('not.exist'); + cy.get(DOCUMENT_DETAILS_FLYOUT_PREVIEW_FOOTER).should('not.exist'); + }); + + it('should open a new flyout when footer link is clicked', () => { + cy.log('open alert preview from related alerts by ancestry'); + cy.get(CORRELATIONS_ANCESTRY_SECTION_TABLE).should('exist'); + clickExpandFromRelatedByAncestry(); + + cy.log('Verify preview section is visible'); + + cy.get(PREVIEW_SECTION).should('exist'); + cy.get(DOCUMENT_DETAILS_FLYOUT_PREVIEW_FOOTER).should('be.visible'); + + cy.log('Click footer link to open alert details flyout'); + openNewFlyout(); + cy.get(PREVIEW_SECTION).should('not.exist'); + cy.get(DOCUMENT_DETAILS_FLYOUT_PREVIEW_FOOTER).should('not.exist'); + + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER).should('be.visible'); + cy.get(DOCUMENT_DETAILS_FLYOUT_FOOTER_TAKE_ACTION_BUTTON).should('be.visible'); + }); + } +); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_overview_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_overview_tab.cy.ts index c4a20c43c6c04..b9c44b4ad5f72 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_overview_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_overview_tab.cy.ts @@ -43,6 +43,8 @@ import { DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_RESPONSE_BUTTON, DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_VALUES_RELATED_ALERTS_BY_SAME_SOURCE_EVENT, DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_ABOUT_SECTION_CONTENT, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HOST_OVERVIEW_LINK, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_USER_OVERVIEW_LINK, } from '../../../../screens/expandable_flyout/alert_details_right_panel_overview_tab'; import { navigateToCorrelationsDetails, @@ -76,6 +78,20 @@ import { import { DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_CORRELATIONS_BUTTON } from '../../../../screens/expandable_flyout/alert_details_left_panel_correlations_tab'; import { DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_THREAT_INTELLIGENCE_BUTTON } from '../../../../screens/expandable_flyout/alert_details_left_panel_threat_intelligence_tab'; import { DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_BUTTON } from '../../../../screens/expandable_flyout/alert_details_left_panel_prevalence_tab'; +import { + HOST_PANEL_HEADER, + HOST_PREVIEW_PANEL_FOOTER, + OPEN_HOST_FLYOUT_LINK, +} from '../../../../screens/hosts/flyout_host_panel'; +import { + USER_PANEL_HEADER, + USER_PREVIEW_PANEL_FOOTER, + OPEN_USER_FLYOUT_LINK, +} from '../../../../screens/users/flyout_user_panel'; +import { + PREVIEW_SECTION, + PREVIEW_BANNER, +} from '../../../../screens/expandable_flyout/alert_details_preview_panel'; describe( 'Alert details expandable flyout right panel overview tab', @@ -216,6 +232,15 @@ describe( 'contain.text', 'host.name' ); + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_TABLE_FIELD_CELL).should( + 'contain.text', + 'user.name' + ); + }); + + // github.com/elastic/security-team/issues/9933 + // Skip when feature flag 'entityAlertPreviewEnabled' is enabled + it('should open entities details when clicking host name and user name', () => { const hostNameCell = DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_TABLE_VALUE_CELL('siem-kibana'); cy.get(hostNameCell).and('have.text', 'siem-kibana'); @@ -225,10 +250,6 @@ describe( collapseDocumentDetailsExpandableFlyoutLeftSection(); - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_TABLE_FIELD_CELL).should( - 'contain.text', - 'user.name' - ); const userNameCell = DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_TABLE_VALUE_CELL('test'); cy.get(userNameCell).should('have.text', 'test'); @@ -236,6 +257,51 @@ describe( cy.get(userNameCell).click(); cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS).should('exist'); }); + + // github.com/elastic/security-team/issues/9933 + // Enable when feature flag 'entityAlertPreviewEnabled' is enabled + it.skip('should open host preview when host name is clicked', () => { + toggleOverviewTabAboutSection(); + + cy.log('should open host preview when clicked on host name'); + + const hostNameCell = + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_TABLE_VALUE_CELL('siem-kibana'); + cy.get(hostNameCell).click(); + + cy.get(PREVIEW_SECTION).should('exist'); + cy.get(PREVIEW_BANNER).should('have.text', 'Preview host details'); + cy.get(HOST_PANEL_HEADER).should('exist'); + cy.get(HOST_PREVIEW_PANEL_FOOTER).should('exist'); + + cy.log('should open host flyout when click on footer link'); + + cy.get(OPEN_HOST_FLYOUT_LINK).click(); + cy.get(HOST_PANEL_HEADER).should('exist'); + cy.get(PREVIEW_SECTION).should('not.exist'); + cy.get(HOST_PREVIEW_PANEL_FOOTER).should('not.exist'); + }); + + // github.com/elastic/security-team/issues/9933 + // Enable when feature flag 'entityAlertPreviewEnabled' is enabled + it.skip('should open user preview when user name is clicked', () => { + toggleOverviewTabAboutSection(); + + const userNameCell = + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HIGHLIGHTED_FIELDS_TABLE_VALUE_CELL('test'); + cy.get(userNameCell).and('have.text', 'test'); + + cy.get(userNameCell).click(); + cy.get(PREVIEW_SECTION).should('exist'); + cy.get(PREVIEW_BANNER).should('have.text', 'Preview user details'); + cy.get(USER_PANEL_HEADER).should('exist'); + cy.get(USER_PREVIEW_PANEL_FOOTER).should('exist'); + + cy.get(OPEN_USER_FLYOUT_LINK).click(); + cy.get(USER_PANEL_HEADER).should('exist'); + cy.get(PREVIEW_SECTION).should('not.exist'); + cy.get(USER_PREVIEW_PANEL_FOOTER).should('not.exist'); + }); }); describe('insights section', () => { @@ -262,6 +328,50 @@ describe( .and('have.class', 'euiButtonGroupButton-isSelected'); }); + // github.com/elastic/security-team/issues/9933 + // Enable when feature flag 'entityAlertPreviewEnabled' is enabled + it.skip('open host preview when host name is clicked', () => { + toggleOverviewTabAboutSection(); + toggleOverviewTabInvestigationSection(); + toggleOverviewTabInsightsSection(); + + cy.log('should open host preview when clicked on host name'); + + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HOST_OVERVIEW_LINK).click(); + + cy.get(PREVIEW_SECTION).should('exist'); + cy.get(PREVIEW_BANNER).should('have.text', 'Preview host details'); + cy.get(HOST_PANEL_HEADER).should('exist'); + cy.get(HOST_PREVIEW_PANEL_FOOTER).should('exist'); + + cy.log('should open host flyout when click on footer link'); + + cy.get(OPEN_HOST_FLYOUT_LINK).click(); + cy.get(HOST_PANEL_HEADER).should('exist'); + cy.get(PREVIEW_SECTION).should('not.exist'); + cy.get(HOST_PREVIEW_PANEL_FOOTER).should('not.exist'); + }); + + // github.com/elastic/security-team/issues/9933 + // Enable when feature flag 'entityAlertPreviewEnabled' is enabled + it.skip('open user preview when user name is clicked', () => { + toggleOverviewTabAboutSection(); + toggleOverviewTabInvestigationSection(); + toggleOverviewTabInsightsSection(); + + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_USER_OVERVIEW_LINK).click(); + + cy.get(PREVIEW_SECTION).should('exist'); + cy.get(PREVIEW_BANNER).should('have.text', 'Preview user details'); + cy.get(USER_PANEL_HEADER).should('exist'); + cy.get(USER_PREVIEW_PANEL_FOOTER).should('exist'); + + cy.get(OPEN_USER_FLYOUT_LINK).click(); + cy.get(USER_PANEL_HEADER).should('exist'); + cy.get(PREVIEW_SECTION).should('not.exist'); + cy.get(USER_PREVIEW_PANEL_FOOTER).should('not.exist'); + }); + it('should display threat intelligence section', () => { toggleOverviewTabAboutSection(); toggleOverviewTabInvestigationSection(); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/pagination.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/pagination.cy.ts index ca75cb8332ab3..150ab83f8aab1 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/pagination.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/pagination.cy.ts @@ -28,7 +28,12 @@ const defaultPageSize = 25; describe( 'Timeline Pagination', { - tags: ['@ess', '@serverless'], + /* + * Tests with feature flag should not be enabled on serverless mki + * so skipping it. When you remove the feature flag, remove the + * skipInServerlessMKI tag as well. + * */ + tags: ['@ess', '@serverless', '@skipInServerlessMKI'], env: { ftrConfig: { kbnServerArgs: [ diff --git a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_correlations_tab.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_correlations_tab.ts index 21f20f8679cdc..dc44deb2d5049 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_correlations_tab.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_correlations_tab.ts @@ -24,6 +24,10 @@ export const CORRELATIONS_ANCESTRY_SECTION_INVESTIGATE_IN_TIMELINE_BUTTON = 'securitySolutionFlyoutCorrelationsDetailsAlertsByAncestrySectionInvestigateInTimeline' ); +export const CORRELATIONS_ANCESTRY_SECTION_PREVIEW_BUTTON = getDataTestSubjectSelector( + 'securitySolutionFlyoutCorrelationsDetailsAlertsByAncestrySectionAlertPreviewButton' +); + export const CORRELATIONS_SOURCE_SECTION_TITLE = getDataTestSubjectSelector( 'securitySolutionFlyoutCorrelationsDetailsAlertsBySourceSectionTitleText' ); @@ -37,6 +41,10 @@ export const CORRELATIONS_SOURCE_SECTION_INVESTIGATE_IN_TIMELINE_BUTTON = 'securitySolutionFlyoutCorrelationsDetailsAlertsBySourceSectionInvestigateInTimeline' ); +export const CORRELATIONS_SOURCE_SECTION_PREVIEW_BUTTON = getDataTestSubjectSelector( + 'securitySolutionFlyoutCorrelationsDetailsAlertsBySourceSectionAlertPreviewButton' +); + export const CORRELATIONS_SESSION_SECTION_TITLE = getDataTestSubjectSelector( 'securitySolutionFlyoutCorrelationsDetailsAlertsBySessionSectionTitleText' ); @@ -50,6 +58,10 @@ export const CORRELATIONS_SESSION_SECTION_INVESTIGATE_IN_TIMELINE_BUTTON = 'securitySolutionFlyoutCorrelationsDetailsAlertsBySessionSectionInvestigateInTimeline' ); +export const CORRELATIONS_SESSION_SECTION_PREVIEW_BUTTON = getDataTestSubjectSelector( + 'securitySolutionFlyoutCorrelationsDetailsAlertsBySessionSectionAlertPreviewButton' +); + export const CORRELATIONS_CASES_SECTION_TITLE = getDataTestSubjectSelector( 'securitySolutionFlyoutCorrelationsDetailsCasesSectionTitleText' ); diff --git a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_entities_tab.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_entities_tab.ts index 37424eeb935fa..fb7ca4fcb5556 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_entities_tab.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_entities_tab.ts @@ -13,11 +13,18 @@ export const DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_ENTITIES_BUTTON = getDataTestS export const DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS_TITLE = getDataTestSubjectSelector( 'securitySolutionFlyoutUsersDetailsTitleText' ); +export const DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS_LINK = getDataTestSubjectSelector( + 'securitySolutionFlyoutUsersDetailsTitleLink' +); export const DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS_RIGHT_SECTION = getDataTestSubjectSelector('securitySolutionFlyoutUsersDetailsRightSection'); export const DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_USER_DETAILS = getDataTestSubjectSelector( 'securitySolutionFlyoutUsersDetailsContent' ); + +export const DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS_LINK = getDataTestSubjectSelector( + 'securitySolutionFlyoutHostsDetailsTitleLink' +); export const DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_HOST_DETAILS_TITLE = getDataTestSubjectSelector( 'securitySolutionFlyoutHostsDetailsTitleText' ); diff --git a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_prevalence_tab.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_prevalence_tab.ts index 4830ef2f28500..5fe3d1ef61338 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_prevalence_tab.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_prevalence_tab.ts @@ -24,3 +24,8 @@ export const DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_TABLE_HOST_PREVALEN getDataTestSubjectSelector('securitySolutionFlyoutPrevalenceDetailsTableHostPrevalenceCell'); export const DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_TABLE_USER_PREVALENCE_CELL = getDataTestSubjectSelector('securitySolutionFlyoutPrevalenceDetailsTableUserPrevalenceCell'); + +export const DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_TABLE_HOST_CELL = + getDataTestSubjectSelector('securitySolutionFlyoutPrevalenceDetailsTableHostCell'); +export const DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_PREVALENCE_TABLE_USER_CELL = + getDataTestSubjectSelector('securitySolutionFlyoutPrevalenceDetailsTableUserCell'); diff --git a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_preview_panel.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_preview_panel.ts new file mode 100644 index 0000000000000..08326d56ef53b --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_preview_panel.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getDataTestSubjectSelector } from '../../helpers/common'; + +/* Preview Section */ + +export const PREVIEW_SECTION = getDataTestSubjectSelector('previewSection'); + +export const PREVIEW_BANNER = getDataTestSubjectSelector('previewSectionBannerText'); + +export const PREVIEW_BACK_BUTTON = getDataTestSubjectSelector('previewSectionBackButton'); + +export const PREVIEW_CLOSE_BUTTON = getDataTestSubjectSelector('previewSectionCloseButton'); + +/* Preview Footer */ + +export const DOCUMENT_DETAILS_FLYOUT_PREVIEW_FOOTER = getDataTestSubjectSelector( + 'securitySolutionFlyoutPreviewFooter' +); +export const DOCUMENT_DETAILS_FLYOUT_PREVIEW_FOOTER_LINK = getDataTestSubjectSelector( + 'securitySolutionFlyoutPreviewFooterLink' +); diff --git a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel_overview_tab.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel_overview_tab.ts index 33e625d1db89a..2dbadb730096e 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel_overview_tab.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel_overview_tab.ts @@ -66,6 +66,12 @@ export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_SECTION_CONTENT = export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_ENTITIES_HEADER = getDataTestSubjectSelector('securitySolutionFlyoutInsightsEntitiesTitleLink'); +export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HOST_OVERVIEW_LINK = getDataTestSubjectSelector( + 'securitySolutionFlyoutInsightsEntitiesHostOverviewLink' +); +export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_USER_OVERVIEW_LINK = getDataTestSubjectSelector( + 'securitySolutionFlyoutInsightsEntitiesUserOverviewLink' +); /* Insights Threat Intelligence */ diff --git a/x-pack/test/security_solution_cypress/cypress/screens/hosts/flyout_host_panel.ts b/x-pack/test/security_solution_cypress/cypress/screens/hosts/flyout_host_panel.ts index 12f0256a24a34..e3173bd17d583 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/hosts/flyout_host_panel.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/hosts/flyout_host_panel.ts @@ -8,3 +8,5 @@ import { getDataTestSubjectSelector } from '../../helpers/common'; export const HOST_PANEL_HEADER = getDataTestSubjectSelector('host-panel-header'); +export const HOST_PREVIEW_PANEL_FOOTER = getDataTestSubjectSelector('host-preview-footer'); +export const OPEN_HOST_FLYOUT_LINK = getDataTestSubjectSelector('open-host-flyout'); diff --git a/x-pack/test/security_solution_cypress/cypress/screens/users/flyout_user_panel.ts b/x-pack/test/security_solution_cypress/cypress/screens/users/flyout_user_panel.ts index 40507311d424d..66205566bde66 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/users/flyout_user_panel.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/users/flyout_user_panel.ts @@ -18,3 +18,6 @@ export const OKTA_MANAGED_DATA_TITLE = `${MANAGED_DATA_SECTION} ${getDataTestSub export const ENTRA_MANAGED_DATA_TITLE = `${MANAGED_DATA_SECTION} ${getDataTestSubjectSelector( 'managed-user-accordion-userAssetEntraLeftSection' )}`; + +export const USER_PREVIEW_PANEL_FOOTER = getDataTestSubjectSelector('user-preview-footer'); +export const OPEN_USER_FLYOUT_LINK = getDataTestSubjectSelector('open-user-flyout'); diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_left_panel_correlations_tab.ts b/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_left_panel_correlations_tab.ts index a86f9a74b18d0..50736a5b7ab9e 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_left_panel_correlations_tab.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_left_panel_correlations_tab.ts @@ -10,6 +10,9 @@ import { CORRELATIONS_SESSION_SECTION_INVESTIGATE_IN_TIMELINE_BUTTON, CORRELATIONS_SOURCE_SECTION_INVESTIGATE_IN_TIMELINE_BUTTON, DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_CORRELATIONS_BUTTON, + CORRELATIONS_ANCESTRY_SECTION_PREVIEW_BUTTON, + CORRELATIONS_SESSION_SECTION_PREVIEW_BUTTON, + CORRELATIONS_SOURCE_SECTION_PREVIEW_BUTTON, } from '../../screens/expandable_flyout/alert_details_left_panel_correlations_tab'; /** @@ -27,15 +30,36 @@ export const openTimelineFromRelatedSourceEvent = () => { }; /** - * Open timeline from the related by source event + * Click expand button from the related by source table + */ +export const clickExpandFromRelatedBySource = (index = 0) => { + cy.get(CORRELATIONS_SOURCE_SECTION_PREVIEW_BUTTON).eq(index).click(); +}; + +/** + * Open timeline from the related by ancestry */ export const openTimelineFromRelatedByAncestry = () => { cy.get(CORRELATIONS_ANCESTRY_SECTION_INVESTIGATE_IN_TIMELINE_BUTTON).click(); }; +/** + * Click expand button from the related by ancestry table + */ +export const clickExpandFromRelatedByAncestry = (index = 0) => { + cy.get(CORRELATIONS_ANCESTRY_SECTION_PREVIEW_BUTTON).eq(index).click(); +}; + /** * Open timeline from the related by source event */ export const openTimelineFromRelatedBySession = () => { cy.get(CORRELATIONS_SESSION_SECTION_INVESTIGATE_IN_TIMELINE_BUTTON).click(); }; + +/** + * Click expand button from the related by session table + */ +export const clickExpandFromRelatedBySession = (index = 0) => { + cy.get(CORRELATIONS_SESSION_SECTION_PREVIEW_BUTTON).eq(index).click(); +}; diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_preview_panel.ts b/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_preview_panel.ts new file mode 100644 index 0000000000000..b3d20d27afbe9 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_preview_panel.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + DOCUMENT_DETAILS_FLYOUT_PREVIEW_FOOTER_LINK, + PREVIEW_BACK_BUTTON, + PREVIEW_CLOSE_BUTTON, +} from '../../screens/expandable_flyout/alert_details_preview_panel'; + +/** + * Close preview panel + */ +export const closePreview = () => { + cy.get(PREVIEW_CLOSE_BUTTON).click(); +}; + +/** + * Go to previous preview + */ +export const goToPreviousPreview = () => { + cy.get(PREVIEW_BACK_BUTTON).click(); +}; + +/** + * Click link in footer to open document details flyout + */ +export const openNewFlyout = () => { + cy.get(DOCUMENT_DETAILS_FLYOUT_PREVIEW_FOOTER_LINK).click(); +}; diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_right_panel.ts b/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_right_panel.ts index 3934b170f43c0..e5cd3a0264b33 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_right_panel.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout/alert_details_right_panel.ts @@ -42,15 +42,15 @@ export const collapseDocumentDetailsExpandableFlyoutLeftSection = () => { /** * Open the Table tab in the document details expandable flyout right section */ -export const openTableTab = () => { - cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB).click(); +export const openTableTab = (index = 0) => { + cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB).eq(index).click(); }; /** * Open the Json tab in the document details expandable flyout right section */ -export const openJsonTab = () => { - cy.get(DOCUMENT_DETAILS_FLYOUT_JSON_TAB).click(); +export const openJsonTab = (index = 0) => { + cy.get(DOCUMENT_DETAILS_FLYOUT_JSON_TAB).eq(index).click(); }; /** diff --git a/x-pack/test/ui_capabilities/common/plugins/foo_plugin/server/index.ts b/x-pack/test/ui_capabilities/common/plugins/foo_plugin/server/index.ts index 4698b8c59c8f4..6443c5a70ee92 100644 --- a/x-pack/test/ui_capabilities/common/plugins/foo_plugin/server/index.ts +++ b/x-pack/test/ui_capabilities/common/plugins/foo_plugin/server/index.ts @@ -6,12 +6,12 @@ */ import { CoreSetup, Plugin } from '@kbn/core/server'; -import { PluginSetupContract as FeaturesPluginSetupContract } from '@kbn/features-plugin/server'; +import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; export const plugin = async () => new FooPlugin(); interface SetupDeps { - features: FeaturesPluginSetupContract; + features: FeaturesPluginSetup; } class FooPlugin implements Plugin { diff --git a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/response_headers.ts b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/response_headers.ts index e731dc083bcf6..797ad2ef8e911 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/platform_security/response_headers.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/platform_security/response_headers.ts @@ -17,6 +17,9 @@ export default function ({ getService }: FtrProviderContext) { let roleAuthc: RoleCredentials; describe('security/response_headers', function () { + // fails on MKI, see https://github.com/elastic/kibana/issues/188714 + this.tags(['failsOnMKI']); + const baseCSP = `script-src 'report-sample' 'self'; worker-src 'report-sample' 'self' blob:; style-src 'report-sample' 'self' 'unsafe-inline'; frame-ancestors 'self'`; const defaultCOOP = 'same-origin'; const defaultPermissionsPolicy = diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/slos/create_slo.ts b/x-pack/test_serverless/api_integration/test_suites/observability/slos/create_slo.ts index ac57613b96dfd..3f0686f175fc9 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/slos/create_slo.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/slos/create_slo.ts @@ -10,8 +10,8 @@ import expect from '@kbn/expect'; import type { GetTransformsResponseSchema } from '@kbn/transform-plugin/common/api_schemas/transforms'; import { SO_SLO_TYPE } from '@kbn/slo-plugin/server/saved_objects'; import { ALL_VALUE } from '@kbn/slo-schema'; - import { + getSLOPipelineId, getSLOSummaryPipelineId, SLO_SUMMARY_TEMP_INDEX_NAME, } from '@kbn/slo-plugin/common/constants'; @@ -169,15 +169,20 @@ export default function ({ getService }: FtrProviderContext) { assertTransformsResponseBody(body, expectedTransforms); }); - it('creates ingest pipeline', async () => { + it('creates ingest pipelines', async () => { const sloRevision = 1; - const pipelineResponse = await esClient.ingest.getPipeline({ - id: getSLOSummaryPipelineId(sloId, sloRevision), + const rollupPipelineResponse = await esClient.ingest.getPipeline({ + id: getSLOPipelineId(sloId, sloRevision), }); - const expectedPipeline = `.slo-observability.summary.pipeline-${sloId}-${sloRevision}`; + const expectedRollupPipeline = `.slo-observability.sli.pipeline-${sloId}-${sloRevision}`; + expect(rollupPipelineResponse[expectedRollupPipeline]).not.to.be(undefined); - expect(pipelineResponse[expectedPipeline]).not.to.be(undefined); - expect(pipelineResponse[expectedPipeline].description).to.be( + const summaryPipelineResponse = await esClient.ingest.getPipeline({ + id: getSLOSummaryPipelineId(sloId, sloRevision), + }); + const expectedSummaryPipeline = `.slo-observability.summary.pipeline-${sloId}-${sloRevision}`; + expect(summaryPipelineResponse[expectedSummaryPipeline]).not.to.be(undefined); + expect(summaryPipelineResponse[expectedSummaryPipeline].description).to.be( `Ingest pipeline for SLO summary data [id: ${sloId}, revision: ${sloRevision}]` ); }); diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/extensions/_get_cell_renderers.ts b/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/extensions/_get_cell_renderers.ts new file mode 100644 index 0000000000000..2a81561199f47 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/extensions/_get_cell_renderers.ts @@ -0,0 +1,97 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import kbnRison from '@kbn/rison'; +import expect from '@kbn/expect'; +import type { FtrProviderContext } from '../../../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const PageObjects = getPageObjects(['common', 'discover', 'unifiedFieldList']); + const esArchiver = getService('esArchiver'); + const testSubjects = getService('testSubjects'); + const dataGrid = getService('dataGrid'); + const dataViews = getService('dataViews'); + const queryBar = getService('queryBar'); + + describe('extension getCellRenderers', () => { + before(async () => { + await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); + }); + + after(async () => { + await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); + }); + + describe('ES|QL mode', () => { + it('should render log.level badge cell', async () => { + const state = kbnRison.encode({ + dataSource: { type: 'esql' }, + query: { + esql: 'from my-example-logs,logstash* | sort @timestamp desc | where `log.level` is not null', + }, + }); + await PageObjects.common.navigateToApp('discover', { + hash: `/?_a=${state}`, + }); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level'); + const firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 0); + const logLevelBadge = await firstCell.findByTestSubject('*logLevelBadgeCell-'); + expect(await logLevelBadge.getVisibleText()).to.be('debug'); + expect(await logLevelBadge.getComputedStyle('background-color')).to.be( + 'rgba(190, 207, 227, 1)' + ); + }); + + it("should not render log.level badge cell if it's not a logs data source", async () => { + const state = kbnRison.encode({ + dataSource: { type: 'esql' }, + query: { + esql: 'from my-example* | sort @timestamp desc | where `log.level` is not null', + }, + }); + await PageObjects.common.navigateToApp('discover', { + hash: `/?_a=${state}`, + }); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level'); + const firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 0); + expect(await firstCell.getVisibleText()).to.be('debug'); + await testSubjects.missingOrFail('*logLevelBadgeCell-'); + }); + }); + + describe('data view mode', () => { + it('should render log.level badge cell', async () => { + await PageObjects.common.navigateToApp('discover'); + await dataViews.switchTo('my-example-logs,logstash*'); + await queryBar.setQuery('log.level:*'); + await queryBar.submitQuery(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level'); + const firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 1); + const logLevelBadge = await firstCell.findByTestSubject('*logLevelBadgeCell-'); + expect(await logLevelBadge.getVisibleText()).to.be('debug'); + expect(await logLevelBadge.getComputedStyle('background-color')).to.be( + 'rgba(190, 207, 227, 1)' + ); + }); + + it("should not render log.level badge cell if it's not a logs data source", async () => { + await PageObjects.common.navigateToApp('discover'); + await dataViews.switchTo('my-example-*'); + await queryBar.setQuery('log.level:*'); + await queryBar.submitQuery(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await PageObjects.unifiedFieldList.clickFieldListItemAdd('log.level'); + const firstCell = await dataGrid.getCellElementExcludingControlColumns(0, 1); + expect(await firstCell.getVisibleText()).to.be('debug'); + await testSubjects.missingOrFail('*logLevelBadgeCell-'); + }); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/index.ts b/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/index.ts index d5bd7a44f2c98..49a046a73dbe3 100644 --- a/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/index.ts +++ b/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/index.ts @@ -40,5 +40,6 @@ export default function ({ getService, getPageObjects, loadTestFile }: FtrProvid loadTestFile(require.resolve('./_data_source_profile')); loadTestFile(require.resolve('./extensions/_get_row_indicator_provider')); loadTestFile(require.resolve('./extensions/_get_doc_viewer')); + loadTestFile(require.resolve('./extensions/_get_cell_renderers')); }); } diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/esql/_esql_view.ts b/x-pack/test_serverless/functional/test_suites/common/discover/esql/_esql_view.ts index f0bed14163b0a..598b89bb0bff1 100644 --- a/x-pack/test_serverless/functional/test_suites/common/discover/esql/_esql_view.ts +++ b/x-pack/test_serverless/functional/test_suites/common/discover/esql/_esql_view.ts @@ -42,6 +42,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover'); // and load a set of makelogs data await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); + await esArchiver.load('test/functional/fixtures/es_archiver/kibana_sample_data_flights'); + await kibanaServer.importExport.load( + 'test/functional/fixtures/kbn_archiver/kibana_sample_data_flights_index_pattern' + ); await kibanaServer.uiSettings.replace(defaultSettings); await PageObjects.svlCommonPage.loginAsAdmin(); await PageObjects.common.navigateToApp('discover'); @@ -49,7 +53,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.timePicker.setDefaultAbsoluteRange(); }); - describe('test', () => { + describe('ES|QL in Discover', () => { it('should render esql view correctly', async function () { await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); @@ -91,7 +95,43 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await testSubjects.missingOrFail('discoverFieldListPanelEditItem'); }); + it('should not render the histogram for indices with no @timestamp field', async function () { + await PageObjects.discover.selectTextBaseLang(); + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + + const testQuery = `from kibana_sample_data_flights | limit 10`; + + await monacoEditor.setCodeEditorValue(testQuery); + await testSubjects.click('querySubmitButton'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + + expect(await testSubjects.exists('TextBasedLangEditor')).to.be(true); + // I am not rendering the histogram for indices with no @timestamp field + expect(await testSubjects.exists('unifiedHistogramChart')).to.be(false); + }); + + it('should render the histogram for indices with no @timestamp field when the ?earliest, ?latest params are in the query', async function () { + await PageObjects.discover.selectTextBaseLang(); + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + + const testQuery = `from kibana_sample_data_flights | limit 10 | where timestamp >= ?earliest and timestamp <= ?latest`; + + await monacoEditor.setCodeEditorValue(testQuery); + await testSubjects.click('querySubmitButton'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + + const fromTime = 'Apr 10, 2018 @ 00:00:00.000'; + const toTime = 'Nov 15, 2018 @ 00:00:00.000'; + await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); + + expect(await testSubjects.exists('TextBasedLangEditor')).to.be(true); + expect(await testSubjects.exists('unifiedHistogramChart')).to.be(true); + }); + it('should perform test query correctly', async function () { + await PageObjects.timePicker.setDefaultAbsoluteRange(); await PageObjects.discover.selectTextBaseLang(); const testQuery = `from logstash-* | limit 10 | stats countB = count(bytes) by geo.dest | sort countB`; diff --git a/x-pack/test_serverless/functional/test_suites/observability/config.screenshots.ts b/x-pack/test_serverless/functional/test_suites/observability/config.screenshots.ts index f9a06826cb755..196de4506f38d 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/config.screenshots.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/config.screenshots.ts @@ -7,7 +7,17 @@ import { createTestConfig } from '../../config.base'; -const enabledActionTypes = ['.index', '.server-log']; +const enabledActionTypes = [ + '.cases-webhook', + '.index', + '.jira', + '.resilient', + '.server-log', + '.servicenow', + '.servicenow-itom', + '.servicenow-sir', + '.swimlane', +]; export default createTestConfig({ serverlessProject: 'oblt', diff --git a/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/home.ts b/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/home.ts index a1c285146e5e5..4dd38ac9143fb 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/home.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/home.ts @@ -48,7 +48,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); it('dataset quality table exists', async () => { - await PageObjects.datasetQuality.navigateTo(); await PageObjects.datasetQuality.waitUntilTableLoaded(); await testSubjects.existOrFail( PageObjects.datasetQuality.testSubjectSelectors.datasetQualityTable diff --git a/x-pack/test_serverless/functional/test_suites/observability/observability_logs_explorer/columns_selection.ts b/x-pack/test_serverless/functional/test_suites/observability/observability_logs_explorer/columns_selection.ts index 0f2b7a8c12e0b..98a9edf649a00 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/observability_logs_explorer/columns_selection.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/observability_logs_explorer/columns_selection.ts @@ -170,9 +170,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should render a popover with cell actions when a chip on content column is clicked', async () => { await retry.tryForTime(TEST_TIMEOUT, async () => { const cellElement = await dataGrid.getCellElement(0, 4); - const logLevelChip = await cellElement.findByTestSubject( - 'dataTablePopoverChip_log.level' - ); + const logLevelChip = await cellElement.findByTestSubject('*logLevelBadge-'); await logLevelChip.click(); // Check Filter In button is present await testSubjects.existOrFail('dataTableCellAction_addToFilterAction_log.level'); @@ -186,9 +184,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should render the table filtered where log.level value is info when filter in action is clicked', async () => { await retry.tryForTime(TEST_TIMEOUT, async () => { const cellElement = await dataGrid.getCellElement(0, 4); - const logLevelChip = await cellElement.findByTestSubject( - 'dataTablePopoverChip_log.level' - ); + const logLevelChip = await cellElement.findByTestSubject('*logLevelBadge-'); await logLevelChip.click(); // Find Filter In button @@ -197,7 +193,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); await filterInButton.click(); - const rowWithLogLevelInfo = await testSubjects.findAll('dataTablePopoverChip_log.level'); + const rowWithLogLevelInfo = await testSubjects.findAll('*logLevelBadge-'); expect(rowWithLogLevelInfo.length).to.be(4); }); @@ -206,9 +202,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should render the table filtered where log.level value is not info when filter out action is clicked', async () => { await retry.tryForTime(TEST_TIMEOUT, async () => { const cellElement = await dataGrid.getCellElement(0, 4); - const logLevelChip = await cellElement.findByTestSubject( - 'dataTablePopoverChip_log.level' - ); + const logLevelChip = await cellElement.findByTestSubject('*logLevelBadge-'); await logLevelChip.click(); // Find Filter Out button @@ -217,7 +211,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); await filterOutButton.click(); - await testSubjects.missingOrFail('dataTablePopoverChip_log.level'); + await testSubjects.missingOrFail('*logLevelBadge-'); }); }); diff --git a/x-pack/test_serverless/functional/test_suites/observability/screenshot_creation/response_ops_docs/cases/index.ts b/x-pack/test_serverless/functional/test_suites/observability/screenshot_creation/response_ops_docs/cases/index.ts index 171215dfbf4d3..4313b1ee1e6f3 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/screenshot_creation/response_ops_docs/cases/index.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/screenshot_creation/response_ops_docs/cases/index.ts @@ -16,5 +16,6 @@ export default function ({ loadTestFile, getService }: FtrProviderContext) { }); loadTestFile(require.resolve('./list_view')); + loadTestFile(require.resolve('./settings')); }); } diff --git a/x-pack/test_serverless/functional/test_suites/observability/screenshot_creation/response_ops_docs/cases/list_view.ts b/x-pack/test_serverless/functional/test_suites/observability/screenshot_creation/response_ops_docs/cases/list_view.ts index 6daca55a125af..72636a1641058 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/screenshot_creation/response_ops_docs/cases/list_view.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/screenshot_creation/response_ops_docs/cases/list_view.ts @@ -67,12 +67,6 @@ export default function ({ getPageObject, getPageObjects, getService }: FtrProvi await svlCommonScreenshots.takeScreenshot('cases', screenshotDirectories, 1700, 1024); }); - it('case settings screenshot', async () => { - await navigateToCasesApp(getPageObject, getService, owner); - await testSubjects.click('configure-case-button'); - await svlCommonScreenshots.takeScreenshot('add-case-connector', screenshotDirectories); - }); - it('case detail screenshot', async () => { await pageObjects.common.navigateToUrlWithBrowserHistory( 'observability', diff --git a/x-pack/test_serverless/functional/test_suites/observability/screenshot_creation/response_ops_docs/cases/settings.ts b/x-pack/test_serverless/functional/test_suites/observability/screenshot_creation/response_ops_docs/cases/settings.ts new file mode 100644 index 0000000000000..2a29ecc84d41d --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/observability/screenshot_creation/response_ops_docs/cases/settings.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 { OBSERVABILITY_OWNER } from '@kbn/cases-plugin/common'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; +import { navigateToCasesApp } from '../../../../../../shared/lib/cases'; + +export default function ({ getPageObject, getPageObjects, getService }: FtrProviderContext) { + const svlCases = getService('svlCases'); + const svlCommonScreenshots = getService('svlCommonScreenshots'); + const screenshotDirectories = ['response_ops_docs', 'observability_cases']; + const testSubjects = getService('testSubjects'); + const owner = OBSERVABILITY_OWNER; + + describe('Observability case settings', function () { + after(async () => { + await svlCases.api.deleteAllCaseItems(); + }); + + it('case settings screenshots', async () => { + await navigateToCasesApp(getPageObject, getService, owner); + await testSubjects.click('configure-case-button'); + await svlCommonScreenshots.takeScreenshot( + 'observability-cases-settings', + screenshotDirectories + ); + await testSubjects.click('add-template'); + await svlCommonScreenshots.takeScreenshot( + 'observability-cases-templates', + screenshotDirectories, + 1400, + 1000 + ); + await testSubjects.click('common-flyout-cancel'); + await testSubjects.click('dropdown-connectors'); + await testSubjects.click('dropdown-connector-add-connector'); + await svlCommonScreenshots.takeScreenshot( + 'observability-cases-add-connector', + screenshotDirectories + ); + await testSubjects.click('euiFlyoutCloseButton'); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/security/screenshot_creation/response_ops_docs/cases/index.ts b/x-pack/test_serverless/functional/test_suites/security/screenshot_creation/response_ops_docs/cases/index.ts index c2a17b8e8e82d..f7aa3c40753e1 100644 --- a/x-pack/test_serverless/functional/test_suites/security/screenshot_creation/response_ops_docs/cases/index.ts +++ b/x-pack/test_serverless/functional/test_suites/security/screenshot_creation/response_ops_docs/cases/index.ts @@ -16,5 +16,6 @@ export default function ({ loadTestFile, getService }: FtrProviderContext) { }); loadTestFile(require.resolve('./list_view')); + loadTestFile(require.resolve('./settings')); }); } diff --git a/x-pack/test_serverless/functional/test_suites/security/screenshot_creation/response_ops_docs/cases/list_view.ts b/x-pack/test_serverless/functional/test_suites/security/screenshot_creation/response_ops_docs/cases/list_view.ts index 01b9d4a55e3c2..4cc91be419104 100644 --- a/x-pack/test_serverless/functional/test_suites/security/screenshot_creation/response_ops_docs/cases/list_view.ts +++ b/x-pack/test_serverless/functional/test_suites/security/screenshot_creation/response_ops_docs/cases/list_view.ts @@ -75,13 +75,6 @@ export default function ({ getPageObject, getPageObjects, getService }: FtrProvi await svlCommonScreenshots.takeScreenshot('cases-home-page', screenshotDirectories); }); - it('case settings screenshot', async () => { - await navigateToCasesApp(getPageObject, getService, owner); - await testSubjects.click('configure-case-button'); - await pageObjects.header.waitUntilLoadingHasFinished(); - await svlCommonScreenshots.takeScreenshot('case-settings', screenshotDirectories); - }); - it('case detail screenshot', async () => { await pageObjects.common.navigateToUrlWithBrowserHistory( 'securitySolution', diff --git a/x-pack/test_serverless/functional/test_suites/security/screenshot_creation/response_ops_docs/cases/settings.ts b/x-pack/test_serverless/functional/test_suites/security/screenshot_creation/response_ops_docs/cases/settings.ts new file mode 100644 index 0000000000000..e6bf2b9b4d4e4 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/security/screenshot_creation/response_ops_docs/cases/settings.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 { SECURITY_SOLUTION_OWNER } from '@kbn/cases-plugin/common'; +import { FtrProviderContext } from '../../../../../ftr_provider_context'; +import { navigateToCasesApp } from '../../../../../../shared/lib/cases'; + +export default function ({ getPageObject, getPageObjects, getService }: FtrProviderContext) { + const pageObjects = getPageObjects(['common', 'header', 'svlCommonPage', 'svlCommonNavigation']); + const svlCases = getService('svlCases'); + const svlCommonScreenshots = getService('svlCommonScreenshots'); + const screenshotDirectories = ['response_ops_docs', 'security_cases']; + const testSubjects = getService('testSubjects'); + const owner = SECURITY_SOLUTION_OWNER; + + describe('security case settings', function () { + after(async () => { + await svlCases.api.deleteAllCaseItems(); + }); + + beforeEach(async () => { + await pageObjects.svlCommonPage.loginWithRole('admin'); + }); + + it('case settings screenshot', async () => { + await navigateToCasesApp(getPageObject, getService, owner); + await testSubjects.click('configure-case-button'); + await pageObjects.header.waitUntilLoadingHasFinished(); + await svlCommonScreenshots.takeScreenshot('security-cases-settings', screenshotDirectories); + await testSubjects.click('add-template'); + await svlCommonScreenshots.takeScreenshot( + 'security-cases-templates', + screenshotDirectories, + 1400, + 1000 + ); + await testSubjects.click('common-flyout-cancel'); + await testSubjects.click('dropdown-connectors'); + await testSubjects.click('dropdown-connector-add-connector'); + await svlCommonScreenshots.takeScreenshot('security-cases-connectors', screenshotDirectories); + await testSubjects.click('euiFlyoutCloseButton'); + }); + }); +} diff --git a/yarn.lock b/yarn.lock index a93585e5860ad..6a28104d98d00 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1658,10 +1658,10 @@ dependencies: object-hash "^1.3.0" -"@elastic/charts@66.0.5": - version "66.0.5" - resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-66.0.5.tgz#0913cd763fc4a4a6570fa617dbb513eba069c45c" - integrity sha512-a5TPbt7qWl0zFXT5jUqtHkRalc6OUppEKm+oZDKZNdwwYOVn4zb/uOvTQoBRYDHb7lqX/1Es1wVwsiIagifvEA== +"@elastic/charts@66.1.0": + version "66.1.0" + resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-66.1.0.tgz#0b2d27532c30e3ddbf80ec7dcf3e94e97af85801" + integrity sha512-oiNsCFfuqZCrDMmPX8RlGEtULhddOJFkN8pxNavD9x9JIwSB6R0gaw29aWJxwnUeROwq241yDijaOpXmIo/lQQ== dependencies: "@popperjs/core" "^2.11.8" bezier-easing "^2.1.0" @@ -3438,6 +3438,10 @@ version "0.0.0" uid "" +"@kbn/avc-banner@link:packages/kbn-avc-banner": + version "0.0.0" + uid "" + "@kbn/axe-config@link:packages/kbn-axe-config": version "0.0.0" uid "" @@ -6186,6 +6190,10 @@ version "0.0.0" uid "" +"@kbn/security-solution-distribution-bar@link:x-pack/packages/security-solution/distribution_bar": + version "0.0.0" + uid "" + "@kbn/security-solution-ess@link:x-pack/plugins/security_solution_ess": version "0.0.0" uid "" @@ -23772,6 +23780,11 @@ node-cache@^5.1.0: dependencies: clone "2.x" +node-diff3@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/node-diff3/-/node-diff3-3.1.2.tgz#49df8d821dc9cbab87bfd6182171d90169613a97" + integrity sha512-wUd9TWy059I8mZdH6G3LPNlAEfxDvXtn/RcyFrbqL3v34WlDxn+Mh4HDhOwWuaMk/ROVepe5tTpnGHbve6Db2g== + node-dir@^0.1.10: version "0.1.17" resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5" @@ -27847,95 +27860,95 @@ sane@^4.0.3: minimist "^1.1.1" walker "~1.0.5" -sass-embedded-android-arm64@1.77.5: - version "1.77.5" - resolved "https://registry.yarnpkg.com/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.77.5.tgz#72247e760d3e765d184822cc8d970b77171c8e83" - integrity sha512-t4yIhK5OUpg1coZxFpDo3BhI2YVj21JxEd5SVI6FfcWD2ESroQWsC4cbq3ejw5aun8R1Kx6xH1EKxO8bSMvn1g== - -sass-embedded-android-arm@1.77.5: - version "1.77.5" - resolved "https://registry.yarnpkg.com/sass-embedded-android-arm/-/sass-embedded-android-arm-1.77.5.tgz#df864165351efd6dd94703791e7d553c0405c46d" - integrity sha512-/DfNYoykqwMFduecqa8n0NH+cS6oLdCPFjwhe92efsOOt5WDYEOlolnhoOENZxqdzvSV+8axL+mHQ1Ypl4MLtg== - -sass-embedded-android-ia32@1.77.5: - version "1.77.5" - resolved "https://registry.yarnpkg.com/sass-embedded-android-ia32/-/sass-embedded-android-ia32-1.77.5.tgz#7ba5d2567c28ddecaed34d8c7ae60aa8bda2d086" - integrity sha512-92dWhEbR0Z2kpjbpfOx4LM9wlNBSnDsRtwpkMUK8udQIE7uF3E4/Fsf/88IJk0MrRkk4iwrsxxiCb1bz2tWnHQ== - -sass-embedded-android-x64@1.77.5: - version "1.77.5" - resolved "https://registry.yarnpkg.com/sass-embedded-android-x64/-/sass-embedded-android-x64-1.77.5.tgz#d35af64ff83931c3fe135f1ffebf15bb5ffa2fcb" - integrity sha512-lFnXz9lRnjRLJ8Y28ONJViID3rDq4p6LJ/9ByPk2ZnSpx5ouUjsu4AfrXKJ0jgHWBaDvSKSxq2fPpt5aMQAEZA== - -sass-embedded-darwin-arm64@1.77.5: - version "1.77.5" - resolved "https://registry.yarnpkg.com/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.77.5.tgz#40bbb6b5df6817955bc2804c2b067a6ce85954ea" - integrity sha512-J3yP6w+xqPrGQE0+sO4Gam6kBDJL5ivgkFNxR0fVlvKeN5qVFYhymp/xGRRMxBrKjohEQtBGP431EzrtvUMFow== - -sass-embedded-darwin-x64@1.77.5: - version "1.77.5" - resolved "https://registry.yarnpkg.com/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.77.5.tgz#5c6741aa7b96e422b689d7dc0ebb68d6ea7b74fe" - integrity sha512-A9fh5tg4s0FidMTG31Vs8TzYZ3Mam/I/tfqvN0g512OhBajp/p2DJvBY+0Br2r+TNH1yGUXf2ZfULuTBFj5u8w== - -sass-embedded-linux-arm64@1.77.5: - version "1.77.5" - resolved "https://registry.yarnpkg.com/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.77.5.tgz#74b5beaf48d2644eeb133d7b0242fcd714dddb4e" - integrity sha512-LoN804X7QsyvT/h8UGcgBMfV1SdT4JRRNV+slBICxoXPKBLXbZm9KyLRCBQcMLLdlXSZdOfZilxUN1Bd2az6OA== - -sass-embedded-linux-arm@1.77.5: - version "1.77.5" - resolved "https://registry.yarnpkg.com/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.77.5.tgz#ee1d4e4bcfb5eac37a9c39c917ba9ff6b3a71245" - integrity sha512-O7gbOWJloxITBZNkpwChFltxofsnDUf+3pz7+q2ETQKvZQ3kUfFENAF37slo0bsHJ7IEpwJK3ZJlnhZvIgfhgw== - -sass-embedded-linux-ia32@1.77.5: - version "1.77.5" - resolved "https://registry.yarnpkg.com/sass-embedded-linux-ia32/-/sass-embedded-linux-ia32-1.77.5.tgz#9c00f8d2070183bc932048a4a32609e9a960c812" - integrity sha512-KHNJymlEmjyJbhGfB34zowohjgMvv/qKVsDX5hPlar+qMh+cxJwfgPln1Zl9bfe9qLObmEV2zFA1rpVBWy4xGQ== - -sass-embedded-linux-musl-arm64@1.77.5: - version "1.77.5" - resolved "https://registry.yarnpkg.com/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.77.5.tgz#42dde205238796b16235ee9de8c538b7cba242f7" - integrity sha512-ZWl8K8rCL4/phm3IPWDADwjnYAiohoaKg7BKjGo+36zv8P0ocoA0A3j4xx7/kjUJWagOmmoTyYxoOu+lo1NaKw== - -sass-embedded-linux-musl-arm@1.77.5: - version "1.77.5" - resolved "https://registry.yarnpkg.com/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.77.5.tgz#7bbfddddbbd115ead551b57065381e7a19b3b3e2" - integrity sha512-TLhJzd1TJ0oX1oULobkWLMDLeErD27WbhdZqxtFvIqzyO+1TZPMwojhRX4YNWmHdmmYhIuXTR9foWxwL3Xjgsg== - -sass-embedded-linux-musl-ia32@1.77.5: - version "1.77.5" - resolved "https://registry.yarnpkg.com/sass-embedded-linux-musl-ia32/-/sass-embedded-linux-musl-ia32-1.77.5.tgz#d2eea17321204be89cee85cb57edc2850a28c7a2" - integrity sha512-83zNSgsIIc+tYQFKepFIlvAvAHnbWSpZ824MjqXJLeCbfzcMO8SZ/q6OA0Zd2SIrf79lCWI4OfPHqp1PI6M7HQ== - -sass-embedded-linux-musl-x64@1.77.5: - version "1.77.5" - resolved "https://registry.yarnpkg.com/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.77.5.tgz#009dec64fb5a7b1849e7b3b5f45e8903c5643d63" - integrity sha512-/SW9ggXZJilbRbKvRHAxEuQM6Yr9piEpvK7/aDevFL2XFvBW9x+dTzpH5jPVEmM0qWdJisS1r5mEv8AXUUdQZg== - -sass-embedded-linux-x64@1.77.5: - version "1.77.5" - resolved "https://registry.yarnpkg.com/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.77.5.tgz#396b55654a4a107277d46675fc5ba68c74f9abb3" - integrity sha512-3EmYeY+K8nMwIy1El9C+mPuONMQyXSCD6Yyztn3G7moPdZTqXrTL7kTJIl+SRq1tCcnOMMGXnBRE7Kpou1wd+w== - -sass-embedded-win32-arm64@1.77.5: - version "1.77.5" - resolved "https://registry.yarnpkg.com/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.77.5.tgz#5152fe180dd65eab012dc3e91a0fd64511540187" - integrity sha512-dwVFOqkyfCRQgQB8CByH+MG93fp7IsfFaPDDCQVzVFAT00+HXk/dWFPMnv65XDDndGwsUE1KlZnjg8iOBDlRdw== - -sass-embedded-win32-ia32@1.77.5: - version "1.77.5" - resolved "https://registry.yarnpkg.com/sass-embedded-win32-ia32/-/sass-embedded-win32-ia32-1.77.5.tgz#e4835703cf958788765df0751b8282a7beca3898" - integrity sha512-1ij/K5d2sHPJkytWiPJLoUOVHJOB6cSWXq7jmedeuGooWnBmqnWycmGkhBAEK/t6t1XgzMPsiJMGiHKh7fnBuA== - -sass-embedded-win32-x64@1.77.5: - version "1.77.5" - resolved "https://registry.yarnpkg.com/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.77.5.tgz#5588366daf0cfe910926a4a45d9bf9c4470f4c14" - integrity sha512-Pn6j0jDGeEAhuuVY0CaZaBa7yNkqimEsbUDYYuQ9xh+XdGvZ86SZf6HXHUVIyQUjHORLwQ5f0XoKYYzKfC0y9w== - -sass-embedded@^1.77.5: - version "1.77.5" - resolved "https://registry.yarnpkg.com/sass-embedded/-/sass-embedded-1.77.5.tgz#c21da62af45b56a3ffb2e4e9a663389efb56b77a" - integrity sha512-JQI8aprHDRSNK5exXsbusswTENQPJxW1QWUcLdwuyESoJClT1zo8e+4cmaV5OAU4abcRC6Av4/RmLocPdjcR3A== +sass-embedded-android-arm64@1.77.8: + version "1.77.8" + resolved "https://registry.yarnpkg.com/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.77.8.tgz#29dd70d04a13142b62a09bec35a6abe9244d58cf" + integrity sha512-EmWHLbEx0Zo/f/lTFzMeH2Du+/I4RmSRlEnERSUKQWVp3aBSO04QDvdxfFezgQ+2Yt/ub9WMqBpma9P/8MPsLg== + +sass-embedded-android-arm@1.77.8: + version "1.77.8" + resolved "https://registry.yarnpkg.com/sass-embedded-android-arm/-/sass-embedded-android-arm-1.77.8.tgz#7de0641036f1f32e0aec4c250561a3fb9907171e" + integrity sha512-GpGL7xZ7V1XpFbnflib/NWbM0euRzineK0iwoo31/ntWKAXGj03iHhGzkSiOwWSFcXgsJJi3eRA5BTmBvK5Q+w== + +sass-embedded-android-ia32@1.77.8: + version "1.77.8" + resolved "https://registry.yarnpkg.com/sass-embedded-android-ia32/-/sass-embedded-android-ia32-1.77.8.tgz#24603c38361c916d181d30af79a23016fd110b37" + integrity sha512-+GjfJ3lDezPi4dUUyjQBxlNKXNa+XVWsExtGvVNkv1uKyaOxULJhubVo2G6QTJJU0esJdfeXf5Ca5/J0ph7+7w== + +sass-embedded-android-x64@1.77.8: + version "1.77.8" + resolved "https://registry.yarnpkg.com/sass-embedded-android-x64/-/sass-embedded-android-x64-1.77.8.tgz#f53d538f57f109d8a8b8bc64d69a2b1f849c13d2" + integrity sha512-YZbFDzGe5NhaMCygShqkeCWtzjhkWxGVunc7ULR97wmxYPQLPeVyx7XFQZc84Aj0lKAJBJS4qRZeqphMqZEJsQ== + +sass-embedded-darwin-arm64@1.77.8: + version "1.77.8" + resolved "https://registry.yarnpkg.com/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.77.8.tgz#beb4f56677b9310c21ee1be48080cb70bbd1f145" + integrity sha512-aifgeVRNE+i43toIkDFFJc/aPLMo0PJ5s5hKb52U+oNdiJE36n65n2L8F/8z3zZRvCa6eYtFY2b7f1QXR3B0LA== + +sass-embedded-darwin-x64@1.77.8: + version "1.77.8" + resolved "https://registry.yarnpkg.com/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.77.8.tgz#fc8a06d98e0d67cdad2e018fbc087fe19a124948" + integrity sha512-/VWZQtcWIOek60Zj6Sxk6HebXA1Qyyt3sD8o5qwbTgZnKitB1iEBuNunyGoAgMNeUz2PRd6rVki6hvbas9hQ6w== + +sass-embedded-linux-arm64@1.77.8: + version "1.77.8" + resolved "https://registry.yarnpkg.com/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.77.8.tgz#0d771159659d5b2e5742fb9fc7f62c0bf5b5d7f0" + integrity sha512-6iIOIZtBFa2YfMsHqOb3qake3C9d/zlKxjooKKnTSo+6g6z+CLTzMXe1bOfayb7yxeenElmFoK1k54kWD/40+g== + +sass-embedded-linux-arm@1.77.8: + version "1.77.8" + resolved "https://registry.yarnpkg.com/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.77.8.tgz#67d73e6726df6d96a4223e1032fe452df3d307ba" + integrity sha512-2edZMB6jf0whx3T0zlgH+p131kOEmWp+I4wnKj7ZMUeokiY4Up05d10hSvb0Q63lOrSjFAWu6P5/pcYUUx8arQ== + +sass-embedded-linux-ia32@1.77.8: + version "1.77.8" + resolved "https://registry.yarnpkg.com/sass-embedded-linux-ia32/-/sass-embedded-linux-ia32-1.77.8.tgz#63294592cba393ba852590ed586897340d32caca" + integrity sha512-63GsFFHWN5yRLTWiSef32TM/XmjhCBx1DFhoqxmj+Yc6L9Z1h0lDHjjwdG6Sp5XTz5EmsaFKjpDgnQTP9hJX3Q== + +sass-embedded-linux-musl-arm64@1.77.8: + version "1.77.8" + resolved "https://registry.yarnpkg.com/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.77.8.tgz#c31b3535e2c027d45155a423f3bebad8a7ed12a6" + integrity sha512-j8cgQxNWecYK+aH8ESFsyam/Q6G+9gg8eJegiRVpA9x8yk3ykfHC7UdQWwUcF22ZcuY4zegrjJx8k+thsgsOVA== + +sass-embedded-linux-musl-arm@1.77.8: + version "1.77.8" + resolved "https://registry.yarnpkg.com/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.77.8.tgz#3ed067de1a4c94d3c9462d26842e7f34e1282d6a" + integrity sha512-nFkhSl3uu9btubm+JBW7uRglNVJ8W8dGfzVqh3fyQJKS1oyBC3vT3VOtfbT9YivXk28wXscSHpqXZwY7bUuopA== + +sass-embedded-linux-musl-ia32@1.77.8: + version "1.77.8" + resolved "https://registry.yarnpkg.com/sass-embedded-linux-musl-ia32/-/sass-embedded-linux-musl-ia32-1.77.8.tgz#b594999e7fd44df31cf231af3b5dc9707081b64c" + integrity sha512-oWveMe+8TFlP8WBWPna/+Ec5TV0CE+PxEutyi0ltSruBds2zxRq9dPVOqrpPcDN9QUx50vNZC0Afgch0aQEd0g== + +sass-embedded-linux-musl-x64@1.77.8: + version "1.77.8" + resolved "https://registry.yarnpkg.com/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.77.8.tgz#fb25d36f4640ddff94c9111733b9ce9ecad25a24" + integrity sha512-2NtRpMXHeFo9kaYxuZ+Ewwo39CE7BTS2JDfXkTjZTZqd8H+8KC53eBh516YQnn2oiqxSiKxm7a6pxbxGZGwXOQ== + +sass-embedded-linux-x64@1.77.8: + version "1.77.8" + resolved "https://registry.yarnpkg.com/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.77.8.tgz#66344634aab8e38f0a8d7a5712a744430bef29d4" + integrity sha512-ND5qZLWUCpOn7LJfOf0gLSZUWhNIysY+7NZK1Ctq+pM6tpJky3JM5I1jSMplNxv5H3o8p80n0gSm+fcjsEFfjQ== + +sass-embedded-win32-arm64@1.77.8: + version "1.77.8" + resolved "https://registry.yarnpkg.com/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.77.8.tgz#b34b9e637ee82fcf84e7af12fa85ddb1e59c2e62" + integrity sha512-7L8zT6xzEvTYj86MvUWnbkWYCNQP+74HvruLILmiPPE+TCgOjgdi750709BtppVJGGZSs40ZuN6mi/YQyGtwXg== + +sass-embedded-win32-ia32@1.77.8: + version "1.77.8" + resolved "https://registry.yarnpkg.com/sass-embedded-win32-ia32/-/sass-embedded-win32-ia32-1.77.8.tgz#284b5d4629c2ca3f406497b9cbb0a9f9a6a85dda" + integrity sha512-7Buh+4bP0WyYn6XPbthkIa3M2vtcR8QIsFVg3JElVlr+8Ng19jqe0t0SwggDgbMX6AdQZC+Wj4F1BprZSok42A== + +sass-embedded-win32-x64@1.77.8: + version "1.77.8" + resolved "https://registry.yarnpkg.com/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.77.8.tgz#01d32c063bbd5c3fe6b04a4ec2cdf690e61bbae7" + integrity sha512-rZmLIx4/LLQm+4GW39sRJW0MIlDqmyV0fkRzTmhFP5i/wVC7cuj8TUubPHw18rv2rkHFfBZKZJTCkPjCS5Z+SA== + +sass-embedded@^1.77.8: + version "1.77.8" + resolved "https://registry.yarnpkg.com/sass-embedded/-/sass-embedded-1.77.8.tgz#d8d885ccd59c6040fcccd345299a115187d65726" + integrity sha512-WGXA6jcaoBo5Uhw0HX/s6z/sl3zyYQ7ZOnLOJzqwpctFcFmU4L07zn51e2VSkXXFpQZFAdMZNqOGz/7h/fvcRA== dependencies: "@bufbuild/protobuf" "^1.0.0" buffer-builder "^0.2.0" @@ -27944,23 +27957,23 @@ sass-embedded@^1.77.5: supports-color "^8.1.1" varint "^6.0.0" optionalDependencies: - sass-embedded-android-arm "1.77.5" - sass-embedded-android-arm64 "1.77.5" - sass-embedded-android-ia32 "1.77.5" - sass-embedded-android-x64 "1.77.5" - sass-embedded-darwin-arm64 "1.77.5" - sass-embedded-darwin-x64 "1.77.5" - sass-embedded-linux-arm "1.77.5" - sass-embedded-linux-arm64 "1.77.5" - sass-embedded-linux-ia32 "1.77.5" - sass-embedded-linux-musl-arm "1.77.5" - sass-embedded-linux-musl-arm64 "1.77.5" - sass-embedded-linux-musl-ia32 "1.77.5" - sass-embedded-linux-musl-x64 "1.77.5" - sass-embedded-linux-x64 "1.77.5" - sass-embedded-win32-arm64 "1.77.5" - sass-embedded-win32-ia32 "1.77.5" - sass-embedded-win32-x64 "1.77.5" + sass-embedded-android-arm "1.77.8" + sass-embedded-android-arm64 "1.77.8" + sass-embedded-android-ia32 "1.77.8" + sass-embedded-android-x64 "1.77.8" + sass-embedded-darwin-arm64 "1.77.8" + sass-embedded-darwin-x64 "1.77.8" + sass-embedded-linux-arm "1.77.8" + sass-embedded-linux-arm64 "1.77.8" + sass-embedded-linux-ia32 "1.77.8" + sass-embedded-linux-musl-arm "1.77.8" + sass-embedded-linux-musl-arm64 "1.77.8" + sass-embedded-linux-musl-ia32 "1.77.8" + sass-embedded-linux-musl-x64 "1.77.8" + sass-embedded-linux-x64 "1.77.8" + sass-embedded-win32-arm64 "1.77.8" + sass-embedded-win32-ia32 "1.77.8" + sass-embedded-win32-x64 "1.77.8" sass-loader@^10.5.1: version "10.5.1"