diff --git a/.buildkite/ftr_configs.yml b/.buildkite/ftr_configs.yml index 9a73a5a00e8d6..052f6623dc1a6 100644 --- a/.buildkite/ftr_configs.yml +++ b/.buildkite/ftr_configs.yml @@ -322,6 +322,7 @@ enabled: - x-pack/test/functional/apps/saved_query_management/config.ts - x-pack/test/functional/apps/security/config.ts - x-pack/test/functional/apps/slo/embeddables/config.ts + - x-pack/test/functional/apps/search_playground/config.ts - x-pack/test/functional/apps/snapshot_restore/config.ts - x-pack/test/functional/apps/spaces/config.ts - x-pack/test/functional/apps/spaces/in_solution_navigation/config.ts diff --git a/.buildkite/pipeline-resource-definitions/kibana-artifacts-snapshot.yml b/.buildkite/pipeline-resource-definitions/kibana-artifacts-snapshot.yml index 841b06dde4a39..3c28f5de81662 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-artifacts-snapshot.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-artifacts-snapshot.yml @@ -20,6 +20,7 @@ spec: spec: env: ELASTIC_SLACK_NOTIFICATIONS_ENABLED: 'true' + SLACK_NOTIFICATIONS_CHANNEL: '#kibana-operations-alerts' allow_rebuilds: true branch_configuration: main 8.14 7.17 default_branch: main diff --git a/.buildkite/pipeline-resource-definitions/kibana-artifacts-staging.yml b/.buildkite/pipeline-resource-definitions/kibana-artifacts-staging.yml index 2429aac93accc..def68475815a7 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-artifacts-staging.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-artifacts-staging.yml @@ -21,6 +21,7 @@ spec: env: RELEASE_BUILD: 'true' ELASTIC_SLACK_NOTIFICATIONS_ENABLED: 'true' + SLACK_NOTIFICATIONS_CHANNEL: '#kibana-operations-alerts' allow_rebuilds: true branch_configuration: 7.17 8.14 repository: elastic/kibana diff --git a/.buildkite/pipeline-resource-definitions/kibana-artifacts-trigger.yml b/.buildkite/pipeline-resource-definitions/kibana-artifacts-trigger.yml index b9f71d514c240..c51728226f9b4 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-artifacts-trigger.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-artifacts-trigger.yml @@ -21,6 +21,7 @@ spec: env: RELEASE_BUILD: 'true' ELASTIC_SLACK_NOTIFICATIONS_ENABLED: 'true' + SLACK_NOTIFICATIONS_CHANNEL: '#kibana-operations-alerts' allow_rebuilds: true branch_configuration: '8.14' default_branch: main diff --git a/.buildkite/pipeline-resource-definitions/kibana-fips-daily.yml b/.buildkite/pipeline-resource-definitions/kibana-fips-daily.yml index 32f78b24e8d23..6679e3006bb00 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-fips-daily.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-fips-daily.yml @@ -19,7 +19,7 @@ spec: description: Run Kibana FIPS smoke tests spec: env: - SLACK_NOTIFICATIONS_CHANNEL: "#kibana-operations-alerts" + SLACK_NOTIFICATIONS_CHANNEL: "#kibana-fips-ftr-errors" ELASTIC_SLACK_NOTIFICATIONS_ENABLED: "true" repository: elastic/kibana branch_configuration: main @@ -30,7 +30,7 @@ spec: schedules: daily: branch: main - cronline: 0 9 * * * America/New_York + cronline: 0 5 * * * America/New_York teams: kibana-operations: access_level: MANAGE_BUILD_AND_READ diff --git a/.buildkite/pipeline-resource-definitions/kibana-purge-cloud-deployments.yml b/.buildkite/pipeline-resource-definitions/kibana-purge-cloud-deployments.yml index 575f895d77980..3b5d3fd84fad5 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-purge-cloud-deployments.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-purge-cloud-deployments.yml @@ -20,6 +20,7 @@ spec: spec: env: ELASTIC_SLACK_NOTIFICATIONS_ENABLED: 'false' + SLACK_NOTIFICATIONS_CHANNEL: '#kibana-operations-alerts' allow_rebuilds: false branch_configuration: main default_branch: main diff --git a/.buildkite/pipeline-resource-definitions/kibana-serverless-security-solution-quality-gate-api-integration.yml b/.buildkite/pipeline-resource-definitions/kibana-serverless-security-solution-quality-gate-api-integration.yml deleted file mode 100644 index 3e8f53b101626..0000000000000 --- a/.buildkite/pipeline-resource-definitions/kibana-serverless-security-solution-quality-gate-api-integration.yml +++ /dev/null @@ -1,46 +0,0 @@ -# yaml-language-server: $schema=https://gist.githubusercontent.com/elasticmachine/988b80dae436cafea07d9a4a460a011d/raw/rre.schema.json -apiVersion: backstage.io/v1alpha1 -kind: Resource -metadata: - name: bk-kibana-serverless-secsol-qg-api-integration - description: Runs the serverless security solution api integration tests for the Quality Gate - links: - - url: 'https://buildkite.com/elastic/kibana-serverless-security-solution-quality-gate-api-integration' - title: Pipeline link -spec: - type: buildkite-pipeline - owner: 'group:kibana-operations' - system: buildkite - implementation: - apiVersion: buildkite.elastic.dev/v1 - kind: Pipeline - metadata: - name: kibana / serverless / security-solution-quality-gate / api-integration - description: Runs the serverless security solution api integration tests for the Quality Gate - spec: - env: {} - allow_rebuilds: true - branch_configuration: '' - default_branch: main - repository: elastic/kibana - pipeline_file: .buildkite/pipelines/security_solution/api_integration.yml - skip_intermediate_builds: false - provider_settings: - build_branches: false - build_pull_requests: false - publish_commit_status: false - trigger_mode: none - build_tags: false - prefix_pull_request_fork_branch_names: false - skip_pull_request_builds_for_existing_commits: false - teams: - everyone: - access_level: BUILD_AND_READ - security-engineering-productivity: - access_level: MANAGE_BUILD_AND_READ - kibana-operations: - access_level: MANAGE_BUILD_AND_READ - appex-qa: - access_level: MANAGE_BUILD_AND_READ - kibana-tech-leads: - access_level: MANAGE_BUILD_AND_READ diff --git a/.buildkite/pipeline-resource-definitions/locations.yml b/.buildkite/pipeline-resource-definitions/locations.yml index bd28f45d799ac..32ab205451dba 100644 --- a/.buildkite/pipeline-resource-definitions/locations.yml +++ b/.buildkite/pipeline-resource-definitions/locations.yml @@ -26,7 +26,6 @@ spec: - https://github.com/elastic/kibana/blob/main/.buildkite/pipeline-resource-definitions/kibana-performance-data-set-extraction-daily.yml - https://github.com/elastic/kibana/blob/main/.buildkite/pipeline-resource-definitions/kibana-purge-cloud-deployments.yml - https://github.com/elastic/kibana/blob/main/.buildkite/pipeline-resource-definitions/kibana-serverless-release.yml - - https://github.com/elastic/kibana/blob/main/.buildkite/pipeline-resource-definitions/kibana-serverless-security-solution-quality-gate-api-integration.yml - https://github.com/elastic/kibana/blob/main/.buildkite/pipeline-resource-definitions/scalability_testing-daily.yml - https://github.com/elastic/kibana/blob/main/.buildkite/pipeline-resource-definitions/security-solution-ess/security-solution-ess.yml - https://github.com/elastic/kibana/blob/main/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-defend-workflows.yml diff --git a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-defend-workflows.yml b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-defend-workflows.yml index b6898c0b87c17..d5e32ca55172c 100644 --- a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-defend-workflows.yml +++ b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-defend-workflows.yml @@ -13,7 +13,7 @@ spec: kind: Pipeline metadata: name: "Kibana / Serverless / Security Solution Quality Gate / Defend Workflows" - description: "[MKI] Executes Cypress tests for the Defend Workflows team" + description: "[MKI] Executes Cypress and API tests for the Defend Workflows team" spec: repository: elastic/kibana pipeline_file: .buildkite/pipelines/security_solution_quality_gate/mki_security_solution_defend_workflows.yml diff --git a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-detection-engine.yml b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-detection-engine.yml index c6ec39a9b69a0..8dc4265b3e6f4 100644 --- a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-detection-engine.yml +++ b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-detection-engine.yml @@ -13,7 +13,7 @@ spec: kind: Pipeline metadata: name: "Kibana / Serverless / Security Solution Quality Gate / Detection Engine" - description: "[MKI] Executes Cypress tests for the Detection Engine team" + description: "[MKI] Executes Cypress and API tests for the Detection Engine team" spec: repository: elastic/kibana pipeline_file: .buildkite/pipelines/security_solution_quality_gate/mki_security_solution_detection_engine.yml diff --git a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-entity-analytics.yml b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-entity-analytics.yml index 294bda432e6ef..9d5bba5f40d1d 100644 --- a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-entity-analytics.yml +++ b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-entity-analytics.yml @@ -13,7 +13,7 @@ spec: kind: Pipeline metadata: name: "Kibana / Serverless / Security Solution Quality Gate / Entity Analytics" - description: "[MKI] Executes Cypress tests for the Entity Analytics team" + description: "[MKI] Executes Cypress and API tests for the Entity Analytics team" spec: repository: elastic/kibana pipeline_file: .buildkite/pipelines/security_solution_quality_gate/mki_security_solution_entity_analytics.yml diff --git a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-explore.yml b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-explore.yml index 87c33534347ed..cd2739fe4a6fb 100644 --- a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-explore.yml +++ b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-explore.yml @@ -13,7 +13,7 @@ spec: kind: Pipeline metadata: name: "Kibana / Serverless / Security Solution Quality Gate / Explore" - description: "[MKI] Executes Cypress tests for the Explore team" + description: "[MKI] Executes Cypress and API tests for the Explore team" spec: repository: elastic/kibana pipeline_file: .buildkite/pipelines/security_solution_quality_gate/mki_security_solution_explore.yml diff --git a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-gen-ai.yml b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-gen-ai.yml index d80c4bfe3acc1..1aeeefe2a0ad8 100644 --- a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-gen-ai.yml +++ b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-gen-ai.yml @@ -13,7 +13,7 @@ spec: kind: Pipeline metadata: name: "Kibana / Serverless / Security Solution Quality Gate / Gen Ai" - description: "[MKI] Executes Cypress tests for the Gen AI team" + description: "[MKI] Executes Cypress and API tests for the Gen AI team" spec: repository: elastic/kibana pipeline_file: .buildkite/pipelines/security_solution_quality_gate/mki_security_solution_gen_ai.yml diff --git a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-investigations.yml b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-investigations.yml index 0ba63a9762f95..955bcf24b1e63 100644 --- a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-investigations.yml +++ b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-investigations.yml @@ -13,7 +13,7 @@ spec: kind: Pipeline metadata: name: "Kibana / Serverless / Security Solution Quality Gate / Investigations" - description: "[MKI] Executes Cypress tests for the Investigations team" + description: "[MKI] Executes Cypress and API tests for the Investigations team" spec: repository: elastic/kibana pipeline_file: .buildkite/pipelines/security_solution_quality_gate/mki_security_solution_investigations.yml diff --git a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-rule-management.yml b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-rule-management.yml index 4579e8961fffb..af0386076dd4d 100644 --- a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-rule-management.yml +++ b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-rule-management.yml @@ -13,7 +13,7 @@ spec: kind: Pipeline metadata: name: "Kibana / Serverless / Security Solution Quality Gate / Rule Management" - description: "[MKI] Executes Cypress tests for the Rule Management team" + description: "[MKI] Executes Cypress and API tests for the Rule Management team" spec: repository: elastic/kibana pipeline_file: .buildkite/pipelines/security_solution_quality_gate/mki_security_solution_rule_management.yml diff --git a/.buildkite/pipelines/security_solution/api_integration.yml b/.buildkite/pipelines/security_solution/api_integration.yml deleted file mode 100644 index abf8d4f3f9e59..0000000000000 --- a/.buildkite/pipelines/security_solution/api_integration.yml +++ /dev/null @@ -1,23 +0,0 @@ -steps: - - command: .buildkite/scripts/pipelines/security_solution_quality_gate/upload_image_metadata.sh - label: "Upload runtime info" - key: upload_runtime_info - agents: - image: family/kibana-ubuntu-2004 - imageProject: elastic-images-prod - provider: gcp - machineType: n2-standard-4 - preemptible: true - timeout_in_minutes: 300 - retry: - automatic: - - exit_status: "-1" - limit: 2 - - - command: "cat .buildkite/pipelines/security_solution/api_integration_serverless_release.yml | buildkite-agent pipeline upload" - label: 'Upload Release pipeline' - if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" - - - command: "cat .buildkite/pipelines/security_solution/api_integration_serverless_periodic.yml | buildkite-agent pipeline upload" - label: 'Upload Periodic Serverless Pipeline' - if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" diff --git a/.buildkite/pipelines/security_solution/api_integration_serverless_periodic.yml b/.buildkite/pipelines/security_solution/api_integration_serverless_periodic.yml deleted file mode 100644 index 56edb10fb64a5..0000000000000 --- a/.buildkite/pipelines/security_solution/api_integration_serverless_periodic.yml +++ /dev/null @@ -1,528 +0,0 @@ -steps: - - group: "API Integration Serverless Periodic Tests" - key: test_execution - steps: - - label: Running exception_workflows:essentials:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_workflows:essentials:qa:serverless - key: exception_workflows:essentials: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: "*" - limit: 2 - - - label: Running exception_operators_date_numeric_types:essentials:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_operators_date_numeric_types:essentials:qa:serverless - key: exception_operators_date_numeric_types:essentials: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: "*" - limit: 2 - - - label: Running exception_operators_keyword:essentials:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_operators_keyword:essentials:qa:serverless - key: exception_operators_keyword:essentials: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: "*" - limit: 2 - - - label: Running exception_operators_ips:essentials:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_operators_ips:essentials:qa:serverless - key: exception_operators_ips:essentials: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: "*" - limit: 2 - - - label: Running exception_operators_long:essentials:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_operators_long:essentials:qa:serverless - key: exception_operators_long:essentials: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 exception_operators_text:essentials:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_operators_text:essentials:qa:serverless - key: exception_operators_text:essentials: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 alerts:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh alerts:qa:serverless - key: alerts: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 alerts:essentials:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh alerts:essentials:qa:serverless - key: alerts:essentials: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 actions:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh actions:qa:serverless - key: actions: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 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 rule_execution_logic:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_execution_logic:qa:serverless - key: rule_execution_logic: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 rule_patch:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_patch:qa:serverless - key: rule_patch: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 rule_patch:essentials:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_patch:essentials:qa:serverless - key: rule_patch:essentials: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 rule_update:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_update:qa:serverless - key: rule_update: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 rule_update:essentials:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_update:essentials:qa:serverless - key: rule_update:essentials: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 rules_management:essentials:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rules_management:essentials:qa:serverless - key: rules_management:essentials: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 prebuilt_rules_management:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh prebuilt_rules_management:qa:serverless - key: prebuilt_rules_management: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 prebuilt_rules_bundled_prebuilt_rules_package:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh prebuilt_rules_bundled_prebuilt_rules_package:qa:serverless - key: prebuilt_rules_bundled_prebuilt_rules_package: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 prebuilt_rules_large_prebuilt_rules_package:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh prebuilt_rules_large_prebuilt_rules_package:qa:serverless - key: prebuilt_rules_large_prebuilt_rules_package: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 prebuilt_rules_update_prebuilt_rules_package:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh prebuilt_rules_update_prebuilt_rules_package:qa:serverless - key: prebuilt_rules_update_prebuilt_rules_package: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 rule_bulk_actions:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_bulk_actions:qa:serverless - key: rule_bulk_actions: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 rule_read:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_read:qa:serverless - key: rule_read: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 rule_import_export:essentials:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_import_export:essentials:qa:serverless - key: rule_import_export:essentials: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 rule_import_export:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_import_export:qa:serverless - key: rule_import_export: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 rule_management:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_management:qa:serverless - key: rule_management: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 rule_read:essentials:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_read:essentials:qa:serverless - key: rule_read:essentials: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 rule_creation:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_creation:qa:serverless - key: rule_creation: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 rule_creation:essentials:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_creation:essentials:qa:serverless - key: rule_creation:essentials: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 rule_delete:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_delete:qa:serverless - key: rule_delete: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 rule_delete:essentials:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_delete:essentials:qa:serverless - key: rule_delete:essentials: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 exception_lists_items:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_lists_items:qa:serverless - key: exception_lists_items: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 lists_items:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh lists_items:qa:serverless - key: lists_items: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 user_roles:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh user_roles:qa:serverless - key: user_roles: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 telemetry:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh telemetry:qa:serverless - key: telemetry: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 entity_analytics:qa:serverless - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh entity_analytics:qa:serverless - key: entity_analytics: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 diff --git a/.buildkite/pipelines/security_solution/api_integration_serverless_release.yml b/.buildkite/pipelines/security_solution/api_integration_serverless_release.yml deleted file mode 100644 index 6d2a8c1716892..0000000000000 --- a/.buildkite/pipelines/security_solution/api_integration_serverless_release.yml +++ /dev/null @@ -1,528 +0,0 @@ -steps: - - group: "API Integration Serverless Release Tests" - key: test_execution - steps: - - label: Running exception_workflows:essentials:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_workflows:essentials:qa:serverless:release - key: exception_workflows:essentials: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: "*" - limit: 2 - - - label: Running exception_operators_date_numeric_types:essentials:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_operators_date_numeric_types:essentials:qa:serverless:release - key: exception_operators_date_numeric_types:essentials: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: "*" - limit: 2 - - - label: Running exception_operators_keyword:essentials:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_operators_keyword:essentials:qa:serverless:release - key: exception_operators_keyword:essentials: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: "*" - limit: 2 - - - label: Running exception_operators_ips:essentials:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_operators_ips:essentials:qa:serverless:release - key: exception_operators_ips:essentials: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: "*" - limit: 2 - - - label: Running exception_operators_long:essentials:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_operators_long:qa:serverless:release - key: exception_operators_long:essentials: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 exception_operators_text:essentials:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_operators_text:essentials:qa:serverless:release - key: exception_operators_text:essentials: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 alerts:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh alerts:qa:serverless:release - key: alerts: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 alerts:essentials:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh alerts:essentials:qa:serverless:release - key: alerts:essentials: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 actions:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh actions:qa:serverless:release - key: actions: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 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 rule_execution_logic:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_execution_logic:qa:serverless:release - key: rule_execution_logic: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 rule_patch:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_patch:qa:serverless:release - key: rule_patch: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 rule_patch:essentials:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_patch:essentials:qa:serverless:release - key: rule_patch:essentials: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 rule_update:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_update:qa:serverless:release - key: rule_update: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 rule_update:essentials:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_update:essentials:qa:serverless:release - key: rule_update:essentials: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 rules_management:essentials:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rules_management:essentials:qa:serverless:release - key: rules_management:essentials: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 prebuilt_rules_management:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh prebuilt_rules_management:qa:serverless:release - key: prebuilt_rules_management: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 prebuilt_rules_bundled_prebuilt_rules_package:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh prebuilt_rules_bundled_prebuilt_rules_package:qa:serverless:release - key: prebuilt_rules_bundled_prebuilt_rules_package: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 prebuilt_rules_large_prebuilt_rules_package:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh prebuilt_rules_large_prebuilt_rules_package:qa:serverless:release - key: prebuilt_rules_large_prebuilt_rules_package: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 prebuilt_rules_update_prebuilt_rules_package:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh prebuilt_rules_update_prebuilt_rules_package:qa:serverless:release - key: prebuilt_rules_update_prebuilt_rules_package: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 rule_bulk_actions:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_bulk_actions:qa:serverless:release - key: rule_bulk_actions: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 rule_read:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_read:qa:serverless:release - key: rule_read: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 rule_import_export:essentials:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_import_export:essentials:qa:serverless:release - key: rule_import_export:essentials: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 rule_import_export:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_import_export:qa:serverless:release - key: rule_import_export: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 rule_management:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_management:qa:serverless:release - key: rule_management: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 rule_read:essentials:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_read:essentials:qa:serverless:release - key: rule_read:essentials: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 rule_creation:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_creation:qa:serverless:release - key: rule_creation: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 rule_creation:essentials:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_creation:essentials:qa:serverless:release - key: rule_creation:essentials: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 rule_delete:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_delete:qa:serverless:release - key: rule_delete: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 rule_delete:essentials:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_delete:essentials:qa:serverless:release - key: rule_delete:essentials: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 exception_lists_items:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_lists_items:qa:serverless:release - key: exception_lists_items: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 lists_items:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh lists_items:qa:serverless:release - key: lists_items: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 user_roles:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh user_roles:qa:serverless:release - key: user_roles: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 telemetry:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh telemetry:qa:serverless:release - key: telemetry: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 entity_analytics:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh entity_analytics:qa:serverless:release - key: entity_analytics: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 diff --git a/.buildkite/pipelines/security_solution_quality_gate/mki_security_solution_detection_engine.yml b/.buildkite/pipelines/security_solution_quality_gate/mki_security_solution_detection_engine.yml index f9ad0d5817783..9e34569d6a808 100644 --- a/.buildkite/pipelines/security_solution_quality_gate/mki_security_solution_detection_engine.yml +++ b/.buildkite/pipelines/security_solution_quality_gate/mki_security_solution_detection_engine.yml @@ -14,40 +14,494 @@ steps: - exit_status: "*" limit: 1 - - command: .buildkite/scripts/pipelines/security_solution_quality_gate/security_solution_cypress/mki_security_solution_cypress.sh cypress:run:qa:serverless:detection_engine - label: 'Serverless MKI QA Detection Engine - Security Solution Cypress Tests' - key: test_detection_engine - env: - BK_TEST_SUITE_KEY: "serverless-cypress-detection-engine" - agents: - image: family/kibana-ubuntu-2004 - imageProject: elastic-images-prod - provider: gcp - machineType: n2-standard-4 - preemptible: true - # TODO : Revise the timeout when the pipeline will be officially integrated with the quality gate. - timeout_in_minutes: 300 - parallelism: 8 - retry: - automatic: - - exit_status: '-1' - limit: 1 + - group: "Serverless MKI QA Detection Engine - Cypress Tests" + key: cypress_test_detections_engine + steps: + - command: .buildkite/scripts/pipelines/security_solution_quality_gate/security_solution_cypress/mki_security_solution_cypress.sh cypress:run:qa:serverless:detection_engine + label: "Serverless MKI QA Detection Engine - Security Solution Cypress Tests" + key: test_detection_engine + env: + BK_TEST_SUITE_KEY: "serverless-cypress-detection-engine" + agents: + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + provider: gcp + machineType: n2-standard-4 + preemptible: true + # TODO : Revise the timeout when the pipeline will be officially integrated with the quality gate. + timeout_in_minutes: 300 + parallelism: 8 + retry: + automatic: + - exit_status: "-1" + limit: 1 - - command: .buildkite/scripts/pipelines/security_solution_quality_gate/security_solution_cypress/mki_security_solution_cypress.sh cypress:run:qa:serverless:detection_engine:exceptions - label: 'Serverless MKI QA Detection Engine - Exceptions - Security Solution Cypress Tests' - key: test_detection_engine_exceptions - env: - BK_TEST_SUITE_KEY: "serverless-cypress-detection-engine" - agents: - image: family/kibana-ubuntu-2004 - imageProject: elastic-images-prod - provider: gcp - machineType: n2-standard-4 - preemptible: true - # TODO : Revise the timeout when the pipeline will be officially integrated with the quality gate. - timeout_in_minutes: 300 - parallelism: 6 - retry: - automatic: - - exit_status: '-1' - limit: 1 + - command: .buildkite/scripts/pipelines/security_solution_quality_gate/security_solution_cypress/mki_security_solution_cypress.sh cypress:run:qa:serverless:detection_engine:exceptions + label: "Serverless MKI QA Detection Engine - Exceptions - Security Solution Cypress Tests" + key: test_detection_engine_exceptions + env: + BK_TEST_SUITE_KEY: "serverless-cypress-detection-engine" + agents: + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + provider: gcp + machineType: n2-standard-4 + preemptible: true + # TODO : Revise the timeout when the pipeline will be officially integrated with the quality gate. + timeout_in_minutes: 300 + parallelism: 6 + retry: + automatic: + - exit_status: "-1" + limit: 1 + + - group: "Serverless MKI QA Detection Engine - API Integration" + key: api_test_detections_engine + steps: + - label: Running exception_lists_items:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_lists_items:qa:serverless + key: exception_lists_items: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 exception_lists_items:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_lists_items:qa:serverless:release + key: exception_lists_items: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 lists_items:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh lists_items:qa:serverless + key: lists_items: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 lists_items:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh entity_analytics:essentials:qa:serverless:release + key: lists_items: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 user_roles:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh user_roles:qa:serverless + key: user_roles: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 user_roles:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh user_roles:qa:serverless:release + key: user_roles: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 telemetry:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh telemetry:qa:serverless + key: telemetry: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 telemetry:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh telemetry:qa:serverless:release + key: telemetry: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 exception_workflows:essentials:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_workflows:essentials:qa:serverless + key: exception_workflows:essentials: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 exception_workflows:essentials:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_workflows:essentials:qa:serverless:release + key: exception_workflows:essentials: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 exception_operators_date_numeric_types:essentials:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_operators_date_numeric_types:essentials:qa:serverless + key: exception_operators_date_numeric_types:essentials: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 exception_operators_date_numeric_types:essentials:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_operators_date_numeric_types:essentials:qa:serverless:release + key: exception_operators_date_numeric_types:essentials: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 exception_operators_keyword:essentials:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_operators_keyword:essentials:qa:serverless + key: exception_operators_keyword:essentials: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 exception_operators_keyword:essentials:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_operators_keyword:essentials:qa:serverless:release + key: exception_operators_keyword:essentials: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 exception_operators_ips:essentials:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_operators_ips:essentials:qa:serverless + key: exception_operators_ips:essentials: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 exception_operators_ips:essentials:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_operators_ips:essentials:qa:serverless:release + key: exception_operators_ips:essentials: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 exception_operators_long:essentials:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_operators_long:essentials:qa:serverless + key: exception_operators_long:essentials: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 exception_operators_long:essentials:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_operators_long:essentials:qa:serverless:release + key: exception_operators_long:essentials: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 exception_operators_text:essentials:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_operators_text:essentials:qa:serverless + key: exception_operators_text:essentials: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 exception_operators_text:essentials:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_operators_text:essentials:qa:serverless:release + key: exception_operators_text:essentials: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 actions:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh actions:qa:serverless + key: actions: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 actions:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh actions:qa:serverless:release + key: actions: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 alerts:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh alerts:qa:serverless + key: alerts: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 alerts:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh alerts:qa:serverless:release + key: alerts: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 alerts:essentials:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh alerts:essentials:qa:serverless + key: alerts:essentials: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 alerts:essentials:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh alerts:essentials:qa:serverless:release + key: alerts:essentials: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 rule_execution_logic:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_execution_logic:qa:serverless + key: rule_execution_logic: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 rule_execution_logic:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_execution_logic:qa:serverless:release + key: rule_execution_logic: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 diff --git a/.buildkite/pipelines/security_solution_quality_gate/mki_security_solution_entity_analytics.yml b/.buildkite/pipelines/security_solution_quality_gate/mki_security_solution_entity_analytics.yml index 9c553176429d0..1b36316ad2307 100644 --- a/.buildkite/pipelines/security_solution_quality_gate/mki_security_solution_entity_analytics.yml +++ b/.buildkite/pipelines/security_solution_quality_gate/mki_security_solution_entity_analytics.yml @@ -32,3 +32,70 @@ steps: automatic: - exit_status: '-1' limit: 1 + + - group: "Serverless MKI QA Entity Analytics - API Integration" + key: api_test_entity_analytics + steps: + - label: Running entity_analytics:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh entity_analytics:qa:serverless + key: entity_analytics: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 entity_analytics:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh entity_analytics:qa:serverless:release + key: entity_analytics: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 entity_analytics:essentials:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh entity_analytics:essentials:qa:serverless + key: entity_analytics:essentials: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 entity_analytics:essentials:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh entity_analytics:essentials:qa:serverless:release + key: entity_analytics:essentials: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 diff --git a/.buildkite/pipelines/security_solution_quality_gate/mki_security_solution_gen_ai.yml b/.buildkite/pipelines/security_solution_quality_gate/mki_security_solution_gen_ai.yml index d6ac5cd764a6f..f392c099560c6 100644 --- a/.buildkite/pipelines/security_solution_quality_gate/mki_security_solution_gen_ai.yml +++ b/.buildkite/pipelines/security_solution_quality_gate/mki_security_solution_gen_ai.yml @@ -32,3 +32,102 @@ steps: automatic: - exit_status: "-1" limit: 1 + + - group: "Serverless MKI QA AI Assistant - API Integration" + key: api_test_ai_assistant + steps: + - label: Running genai:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + 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 genai:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + 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 + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh nlp_cleanup_task:complete:qa:serverless + key: nlp_cleanup_task:complete: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:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + 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 + 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:essentials:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh nlp_cleanup_task:essentials:qa:serverless + key: nlp_cleanup_task:essentials: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:essentials:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh nlp_cleanup_task:essentials:qa:serverless:release + key: nlp_cleanup_task:essentials: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 diff --git a/.buildkite/pipelines/security_solution_quality_gate/mki_security_solution_rule_management.yml b/.buildkite/pipelines/security_solution_quality_gate/mki_security_solution_rule_management.yml index bc46cdffb3627..485a1391b57d9 100644 --- a/.buildkite/pipelines/security_solution_quality_gate/mki_security_solution_rule_management.yml +++ b/.buildkite/pipelines/security_solution_quality_gate/mki_security_solution_rule_management.yml @@ -14,40 +14,654 @@ steps: - exit_status: "*" limit: 1 - - command: .buildkite/scripts/pipelines/security_solution_quality_gate/security_solution_cypress/mki_security_solution_cypress.sh cypress:run:qa:serverless:rule_management - label: 'Serverless MKI QA Rule Management - Security Solution Cypress Tests' - key: test_rule_management - env: - BK_TEST_SUITE_KEY: "serverless-cypress-rule-management" - agents: - image: family/kibana-ubuntu-2004 - imageProject: elastic-images-prod - provider: gcp - machineType: n2-standard-4 - preemptible: true - # TODO : Revise the timeout when the pipeline will be officially integrated with the quality gate. - timeout_in_minutes: 300 - parallelism: 8 - retry: - automatic: - - exit_status: '-1' - limit: 1 + - group: "Serverless MKI QA Rule Management - Cypress Test" + key: cypress_test_rule_management + steps: + - command: .buildkite/scripts/pipelines/security_solution_quality_gate/security_solution_cypress/mki_security_solution_cypress.sh cypress:run:qa:serverless:rule_management + label: "Serverless MKI QA Rule Management - Security Solution Cypress Tests" + key: test_rule_management + env: + BK_TEST_SUITE_KEY: "serverless-cypress-rule-management" + agents: + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + provider: gcp + machineType: n2-standard-4 + preemptible: true + # TODO : Revise the timeout when the pipeline will be officially integrated with the quality gate. + timeout_in_minutes: 300 + parallelism: 8 + retry: + automatic: + - exit_status: "-1" + limit: 1 - - command: .buildkite/scripts/pipelines/security_solution_quality_gate/security_solution_cypress/mki_security_solution_cypress.sh cypress:run:qa:serverless:rule_management:prebuilt_rules - label: 'Serverless MKI QA Rule Management - Prebuilt Rules - Security Solution Cypress Tests' - key: test_rule_management_prebuilt_rules - env: - BK_TEST_SUITE_KEY: "serverless-cypress-rule-management" - agents: - image: family/kibana-ubuntu-2004 - imageProject: elastic-images-prod - provider: gcp - machineType: n2-standard-4 - preemptible: true - # TODO : Revise the timeout when the pipeline will be officially integrated with the quality gate. - timeout_in_minutes: 300 - parallelism: 4 - retry: - automatic: - - exit_status: '-1' - limit: 1 + - command: .buildkite/scripts/pipelines/security_solution_quality_gate/security_solution_cypress/mki_security_solution_cypress.sh cypress:run:qa:serverless:rule_management:prebuilt_rules + label: "Serverless MKI QA Rule Management - Prebuilt Rules - Security Solution Cypress Tests" + key: test_rule_management_prebuilt_rules + env: + BK_TEST_SUITE_KEY: "serverless-cypress-rule-management" + agents: + image: family/kibana-ubuntu-2004 + imageProject: elastic-images-prod + provider: gcp + machineType: n2-standard-4 + preemptible: true + # TODO : Revise the timeout when the pipeline will be officially integrated with the quality gate. + timeout_in_minutes: 300 + parallelism: 4 + retry: + automatic: + - exit_status: "-1" + limit: 1 + + - group: "Serverless MKI QA Rule Management - API Integration" + key: api_test_rule_management + steps: + - label: Running rule_creation:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_creation:qa:serverless + key: rule_creation: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 rule_creation:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_creation:qa:serverless:release + key: rule_creation: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 rule_creation:essentials:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_creation:essentials:qa:serverless + key: rule_creation:essentials: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 rule_creation:essentials:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_creation:essentials:qa:serverless:release + key: rule_creation:essentials: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 rule_update:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_update:qa:serverless + key: rule_update: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 rule_update:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_update:qa:serverless:release + key: rule_update: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 rule_update:essentials:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_update:essentials:qa:serverless + key: rule_update:essentials: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 rule_update:essentials:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_update:essentials:qa:serverless:release + key: rule_update:essentials: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 rule_patch:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_patch:qa:serverless + key: rule_patch: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 rule_patch:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_patch:qa:serverless:release + key: rule_patch: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 rule_patch:essentials:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_patch:essentials:qa:serverless + key: rule_patch:essentials: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 rule_patch:essentials:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_patch:essentials:qa:serverless:release + key: rule_patch:essentials: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 prebuilt_rules_management:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh prebuilt_rules_management:qa:serverless + key: prebuilt_rules_management: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 prebuilt_rules_management:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh prebuilt_rules_management:qa:serverless:release + key: prebuilt_rules_management: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 prebuilt_rules_bundled_prebuilt_rules_package:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh prebuilt_rules_bundled_prebuilt_rules_package:qa:serverless + key: prebuilt_rules_bundled_prebuilt_rules_package: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 prebuilt_rules_bundled_prebuilt_rules_package:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh prebuilt_rules_bundled_prebuilt_rules_package:qa:serverless:release + key: prebuilt_rules_bundled_prebuilt_rules_package: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 prebuilt_rules_large_prebuilt_rules_package:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh prebuilt_rules_large_prebuilt_rules_package:qa:serverless + key: prebuilt_rules_large_prebuilt_rules_package: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 prebuilt_rules_large_prebuilt_rules_package:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh prebuilt_rules_large_prebuilt_rules_package:qa:serverless:release + key: prebuilt_rules_large_prebuilt_rules_package: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 prebuilt_rules_update_prebuilt_rules_package:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh prebuilt_rules_update_prebuilt_rules_package:qa:serverless + key: prebuilt_rules_update_prebuilt_rules_package: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 prebuilt_rules_update_prebuilt_rules_package:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh prebuilt_rules_update_prebuilt_rules_package:qa:serverless:release + key: prebuilt_rules_update_prebuilt_rules_package: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 rule_delete:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_delete:qa:serverless + key: rule_delete: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 rule_delete:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_delete:qa:serverless:release + key: rule_delete: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 rule_delete:essentials:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_delete:essentials:qa:serverless + key: rule_delete:essentials: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 rule_delete:essentials:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_delete:essentials:qa:serverless:release + key: rule_delete:essentials: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 rule_import_export:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_import_export:qa:serverless + key: rule_import_export: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 rule_import_export:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_import_export:qa:serverless:release + key: rule_import_export: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 rule_import_export:essentials:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_import_export:essentials:qa:serverless + key: rule_import_export:essentials: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 rule_import_export:essentials:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_import_export:essentials:qa:serverless:release + key: rule_import_export:essentials: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 rule_management:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_management:qa:serverless + key: rule_management: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 rule_management:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_management:qa:serverless:release + key: rule_management: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 rule_bulk_actions:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_bulk_actions:qa:serverless + key: rule_bulk_actions: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 rule_bulk_actions:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_bulk_actions:qa:serverless:release + key: rule_bulk_actions: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 rule_read:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_read:qa:serverless + key: rule_read: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 rule_read:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_read:qa:serverless:release + key: rule_read: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 rule_read:essentials:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_read:essentials:qa:serverless + key: rule_read:essentials: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 rule_read:essentials:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rule_read:essentials:qa:serverless:release + key: rule_read:essentials: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 rules_management:essentials:qa:serverless + if: "build.env('KIBANA_MKI_QUALITY_GATE') != '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rules_management:essentials:qa:serverless + key: rules_management:essentials: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 rules_management:essentials:qa:serverless:release + if: "build.env('KIBANA_MKI_QUALITY_GATE') == '1'" + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh rules_management:essentials:qa:serverless:release + key: rules_management:essentials: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 diff --git a/.buildkite/scripts/pipelines/security_solution_quality_gate/upload_image_metadata.sh b/.buildkite/scripts/pipelines/security_solution_quality_gate/upload_image_metadata.sh index f47f5d4a41bdf..3f83ffe74bdb8 100644 --- a/.buildkite/scripts/pipelines/security_solution_quality_gate/upload_image_metadata.sh +++ b/.buildkite/scripts/pipelines/security_solution_quality_gate/upload_image_metadata.sh @@ -1,5 +1,13 @@ #!/bin/bash +if [ "$KIBANA_MKI_QUALITY_GATE" == "1" ]; then + echo "Triggered by quality gate!" + triggered_by="Serverless Quality Gate." +else + echo "Triggered by Serverless Kibana Periodic Pipeline." + triggered_by="Serverless Kibana Periodic Pipeline." +fi + KIBANA_BASE_IMAGE="docker.elastic.co/kibana-ci/kibana-serverless" KIBANA_LATEST=${KIBANA_BASE_IMAGE}:latest @@ -16,10 +24,17 @@ vcs_url=$(docker inspect ${KBN_IMAGE} | jq -r '.[0].Config.Labels."org.label-sch version=$(docker inspect ${KBN_IMAGE} | jq -r '.[0].Config.Labels."org.label-schema.version"') markdown_text=""" - # Kibana Container Metadata - - Build Date : $build_date - - Github Commit Hash : $vcs_ref - - Github Repo : $vcs_url - - Version : $version +#### $triggered_by + +- Triggered from buildkite pipeline : $BUILDKITE_TRIGGERED_FROM_BUILD_PIPELINE_SLUG +- Triggered from build : $BUILDKITE_TRIGGERED_FROM_BUILD_NUMBER + +--- + +#### Kibana Container Metadata +- Build Date : $build_date +- Github Commit Hash : $vcs_ref +- Github Repo : $vcs_url +- Version : $version """ echo "${markdown_text//[*\\_]/\\&}" | buildkite-agent annotate --style "info" \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js index ee3d32c5c1171..52807d4b45e62 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1058,6 +1058,7 @@ module.exports = { 'x-pack/plugins/elastic_assistant/**/*.{ts,tsx}', 'x-pack/packages/kbn-elastic-assistant/**/*.{ts,tsx}', 'x-pack/packages/kbn-elastic-assistant-common/**/*.{ts,tsx}', + 'x-pack/packages/kbn-langchain/**/*.{ts,tsx}', 'x-pack/packages/security-solution/**/*.{ts,tsx}', 'x-pack/plugins/security_solution/**/*.{ts,tsx}', 'x-pack/plugins/security_solution_ess/**/*.{ts,tsx}', @@ -1071,6 +1072,7 @@ module.exports = { 'x-pack/plugins/elastic_assistant/**/*.{test,mock,test_helper}.{ts,tsx}', 'x-pack/packages/kbn-elastic-assistant/**/*.{test,mock,test_helper}.{ts,tsx}', 'x-pack/packages/kbn-elastic-assistant-common/**/*.{test,mock,test_helper}.{ts,tsx}', + 'x-pack/packages/kbn-langchain/**/*.{test,mock,test_helper}.{ts,tsx}', 'x-pack/packages/security-solution/**/*.{test,mock,test_helper}.{ts,tsx}', 'x-pack/plugins/security_solution/**/*.{test,mock,test_helper}.{ts,tsx}', 'x-pack/plugins/security_solution_ess/**/*.{test,mock,test_helper}.{ts,tsx}', @@ -1090,6 +1092,7 @@ module.exports = { 'x-pack/plugins/elastic_assistant/**/*.{ts,tsx}', 'x-pack/packages/kbn-elastic-assistant/**/*.{ts,tsx}', 'x-pack/packages/kbn-elastic-assistant-common/**/*.{ts,tsx}', + 'x-pack/packages/kbn-langchain/**/*.{ts,tsx}', 'x-pack/packages/security-solution/**/*.{ts,tsx}', 'x-pack/plugins/security_solution/**/*.{ts,tsx}', 'x-pack/plugins/security_solution_ess/**/*.{ts,tsx}', @@ -1128,6 +1131,7 @@ module.exports = { 'x-pack/plugins/elastic_assistant/**/*.{js,mjs,ts,tsx}', 'x-pack/packages/kbn-elastic-assistant/**/*.{js,mjs,ts,tsx}', 'x-pack/packages/kbn-elastic-assistant-common/**/*.{js,mjs,ts,tsx}', + 'x-pack/packages/kbn-langchain/**/*.{js,mjs,ts,tsx}', 'x-pack/packages/security-solution/**/*.{js,mjs,ts,tsx}', 'x-pack/plugins/security_solution/**/*.{js,mjs,ts,tsx}', 'x-pack/plugins/security_solution_ess/**/*.{js,mjs,ts,tsx}', diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d160dda238f8d..e88634c4220d1 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -81,7 +81,7 @@ packages/kbn-ci-stats-shipper-cli @elastic/kibana-operations packages/kbn-cli-dev-mode @elastic/kibana-operations packages/cloud @elastic/kibana-core x-pack/plugins/cloud_integrations/cloud_chat @elastic/kibana-core -x-pack/plugins/cloud_integrations/cloud_data_migration @elastic/platform-onboarding +x-pack/plugins/cloud_integrations/cloud_data_migration @elastic/kibana-management x-pack/plugins/cloud_defend @elastic/kibana-cloud-security-posture x-pack/plugins/cloud_integrations/cloud_experiments @elastic/kibana-core x-pack/plugins/cloud_integrations/cloud_full_story @elastic/kibana-core @@ -470,9 +470,9 @@ x-pack/plugins/global_search_providers @elastic/appex-sharedux x-pack/test/plugin_functional/plugins/global_search_test @elastic/kibana-core x-pack/plugins/graph @elastic/kibana-visualizations x-pack/plugins/grokdebugger @elastic/kibana-management -packages/kbn-guided-onboarding @elastic/platform-onboarding -examples/guided_onboarding_example @elastic/platform-onboarding -src/plugins/guided_onboarding @elastic/platform-onboarding +packages/kbn-guided-onboarding @elastic/appex-sharedux +examples/guided_onboarding_example @elastic/appex-sharedux +src/plugins/guided_onboarding @elastic/appex-sharedux packages/kbn-handlebars @elastic/kibana-security packages/kbn-hapi-mocks @elastic/kibana-core packages/kbn-health-gateway-server @elastic/kibana-core @@ -517,6 +517,7 @@ src/plugins/kibana_react @elastic/appex-sharedux src/plugins/kibana_usage_collection @elastic/kibana-core src/plugins/kibana_utils @elastic/appex-sharedux x-pack/plugins/kubernetes_security @elastic/kibana-cloud-security-posture +x-pack/packages/kbn-langchain @elastic/security-generative-ai packages/kbn-language-documentation-popover @elastic/kibana-esql x-pack/examples/lens_config_builder_example @elastic/kibana-visualizations packages/kbn-lens-embeddable-utils @elastic/obs-ux-infra_services-team @elastic/kibana-visualizations @@ -817,7 +818,6 @@ packages/kbn-shared-ux-utility @elastic/appex-sharedux x-pack/plugins/observability_solution/slo @elastic/obs-ux-management-team x-pack/packages/kbn-slo-schema @elastic/obs-ux-management-team x-pack/plugins/snapshot_restore @elastic/kibana-management -packages/solution-nav/es @elastic/appex-sharedux @elastic/enterprise-search-frontend packages/solution-nav/oblt @elastic/appex-sharedux @elastic/obs-ux-management-team packages/kbn-some-dev-log @elastic/kibana-operations packages/kbn-sort-package-json @elastic/kibana-operations @@ -1149,8 +1149,8 @@ x-pack/test/observability_ai_assistant_functional @elastic/obs-ai-assistant /src/plugins/unified_doc_viewer/public/components/doc_viewer_logs_overview @elastic/obs-ux-logs-team # Observability onboarding tour -/x-pack/plugins/observability_solution/observability_shared/public/components/tour @elastic/platform-onboarding -/x-pack/test/functional/apps/infra/tour.ts @elastic/platform-onboarding +/x-pack/plugins/observability_solution/observability_shared/public/components/tour @elastic/appex-sharedux +/x-pack/test/functional/apps/infra/tour.ts @elastic/appex-sharedux # Observability settings /x-pack/plugins/observability_solution/observability/server/ui_settings.ts @elastic/obs-docs @@ -1345,6 +1345,8 @@ x-pack/plugins/cloud_integrations/cloud_full_story/server/config.ts @elastic/kib /x-pack/test_serverless/functional/test_suites/common/management/landing_page.ts @elastic/kibana-management /x-pack/test_serverless/functional/test_suites/common/dev_tools/ @elastic/kibana-management /x-pack/test_serverless/**/test_suites/common/grok_debugger/ @elastic/kibana-management +/x-pack/test/api_integration/apis/management/ @elastic/kibana-management +/x-pack/test/functional/apps/rollup_job/ @elastic/kibana-management #CC# /x-pack/plugins/cross_cluster_replication/ @elastic/kibana-management @@ -1662,7 +1664,7 @@ x-pack/plugins/security_solution/server/lib/security_integrations @elastic/secur /src/plugins/kibana_react/public/page_template/ @elastic/eui-team @elastic/appex-sharedux # Landing page for guided onboarding in Home plugin -/src/plugins/home/public/application/components/guided_onboarding @elastic/platform-onboarding +/src/plugins/home/public/application/components/guided_onboarding @elastic/appex-sharedux # Changes to translation files should not ping code reviewers x-pack/plugins/translations/translations diff --git a/.github/workflows/alert-failed-test.yml b/.github/workflows/alert-failed-test.yml new file mode 100644 index 0000000000000..03d46cb65fcfd --- /dev/null +++ b/.github/workflows/alert-failed-test.yml @@ -0,0 +1,28 @@ +on: + issue_comment: + types: [created] + +jobs: + issue_alert: + name: Alert on failed test + if: | + !github.event.issue.pull_request + && github.event.comment.user.login == 'kibanamachine' + runs-on: ubuntu-latest + steps: + - name: Checkout kibana-operations + uses: actions/checkout@v4 + with: + repository: 'elastic/kibana-operations' + ref: main + path: ./kibana-operations + token: ${{secrets.KIBANAMACHINE_TOKEN}} + + - name: Label failed test issue + working-directory: ./kibana-operations/triage + env: + GITHUB_TOKEN: ${{secrets.KIBANAMACHINE_TOKEN}} + SLACK_TOKEN: ${{secrets.SLACK_TOKEN_FAILED_TEST_NOTIFIER}} + run: | + npm ci --omit=dev + node failed-test-alert ${{github.event.issue.number}} || true diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index 0d8591b85a84c..df3525ef778f4 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-05-20 +date: 2024-05-23 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 e9a421e888be2..088b6fd315f53 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-05-20 +date: 2024-05-23 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 e02245146f91b..c6c3fefde138f 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiAssistantManagementSelection'] --- import aiAssistantManagementSelectionObj from './ai_assistant_management_selection.devdocs.json'; diff --git a/api_docs/aiops.devdocs.json b/api_docs/aiops.devdocs.json index d9bcfc2a0c8ca..b0444a67e7314 100644 --- a/api_docs/aiops.devdocs.json +++ b/api_docs/aiops.devdocs.json @@ -1428,7 +1428,127 @@ ], "enums": [], "misc": [], - "objects": [] + "objects": [], + "start": { + "parentPluginId": "aiops", + "id": "def-public.AiopsPluginStart", + "type": "Interface", + "tags": [], + "label": "AiopsPluginStart", + "description": [], + "path": "x-pack/plugins/aiops/public/types/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "aiops", + "id": "def-public.AiopsPluginStart.getPatternAnalysisAvailable", + "type": "Function", + "tags": [], + "label": "getPatternAnalysisAvailable", + "description": [], + "signature": [ + "() => Promise<(dataView: ", + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + }, + ") => Promise>" + ], + "path": "x-pack/plugins/aiops/public/types/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "aiops", + "id": "def-public.AiopsPluginStart.PatternAnalysisComponent", + "type": "CompoundType", + "tags": [], + "label": "PatternAnalysisComponent", + "description": [], + "signature": [ + "React.ComponentClass<", + "LogCategorizationEmbeddableWrapperProps", + ", any> | React.FunctionComponent<", + "LogCategorizationEmbeddableWrapperProps", + ">" + ], + "path": "x-pack/plugins/aiops/public/types/index.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "aiops", + "id": "def-public.AiopsPluginStart.ChangePointDetectionComponent", + "type": "Function", + "tags": [], + "label": "ChangePointDetectionComponent", + "description": [], + "signature": [ + "React.FunctionComponent<", + "ChangePointDetectionProps", + ">" + ], + "path": "x-pack/plugins/aiops/public/types/index.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "aiops", + "id": "def-public.AiopsPluginStart.ChangePointDetectionComponent.$1", + "type": "CompoundType", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "P & { children?: React.ReactNode; }" + ], + "path": "node_modules/@types/react/index.d.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "aiops", + "id": "def-public.AiopsPluginStart.ChangePointDetectionComponent.$2", + "type": "Any", + "tags": [], + "label": "context", + "description": [], + "signature": [ + "any" + ], + "path": "node_modules/@types/react/index.d.ts", + "deprecated": false, + "trackAdoption": false + } + ] + } + ], + "lifecycle": "start", + "initialIsOpen": true + }, + "setup": { + "parentPluginId": "aiops", + "id": "def-public.AiopsPluginSetup", + "type": "Type", + "tags": [], + "label": "AiopsPluginSetup", + "description": [], + "signature": [ + "void" + ], + "path": "x-pack/plugins/aiops/public/types/index.ts", + "deprecated": false, + "trackAdoption": false, + "lifecycle": "setup", + "initialIsOpen": true + } }, "server": { "classes": [], diff --git a/api_docs/aiops.mdx b/api_docs/aiops.mdx index 7ecce04ce1e65..e6d918ab4e086 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiops'] --- import aiopsObj from './aiops.devdocs.json'; @@ -21,10 +21,16 @@ Contact [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) for questi | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 67 | 0 | 4 | 1 | +| 74 | 0 | 9 | 2 | ## Client +### Setup + + +### Start + + ### Functions diff --git a/api_docs/alerting.mdx b/api_docs/alerting.mdx index b28eb1bfdaf88..909da7faa611f 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'alerting'] --- import alertingObj from './alerting.devdocs.json'; diff --git a/api_docs/apm.devdocs.json b/api_docs/apm.devdocs.json index 6931292f8d133..84ad7ebed719e 100644 --- a/api_docs/apm.devdocs.json +++ b/api_docs/apm.devdocs.json @@ -144,7 +144,7 @@ "section": "def-common.NonEmptyStringBrand", "text": "NonEmptyStringBrand" }, - ">; }; })>; }" + ">; } & { kuery?: string | undefined; rangeFrom?: string | undefined; rangeTo?: string | undefined; }; })>; }" ], "path": "x-pack/plugins/observability_solution/apm/public/plugin.ts", "deprecated": false, diff --git a/api_docs/apm.mdx b/api_docs/apm.mdx index 2c3da0893ff2a..183b5565a101a 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-05-20 +date: 2024-05-23 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 f50b0eea77370..9befbd0d57fef 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apmDataAccess'] --- import apmDataAccessObj from './apm_data_access.devdocs.json'; diff --git a/api_docs/asset_manager.mdx b/api_docs/asset_manager.mdx index b0ff0227b6d01..9547456bbad1a 100644 --- a/api_docs/asset_manager.mdx +++ b/api_docs/asset_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/assetManager title: "assetManager" image: https://source.unsplash.com/400x175/?github description: API docs for the assetManager plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'assetManager'] --- import assetManagerObj from './asset_manager.devdocs.json'; diff --git a/api_docs/assets_data_access.mdx b/api_docs/assets_data_access.mdx index 401513ef27e18..bc09178690eda 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-05-20 +date: 2024-05-23 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 31fbbf7e94578..57dd64957ff08 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-05-20 +date: 2024-05-23 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 bba0e4c29bab6..51a3dec58b078 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-05-20 +date: 2024-05-23 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 24ed742c77f02..eba88a82cb814 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-05-20 +date: 2024-05-23 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 1c3da2e8f7236..170dad33bf8de 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-05-20 +date: 2024-05-23 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 1307d78b19c43..0681a83862cfe 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-05-20 +date: 2024-05-23 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 ae1f4c9893e4f..5d7c4527a9033 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-05-20 +date: 2024-05-23 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 3c32678ea6a9d..4a545d6aeb020 100644 --- a/api_docs/cloud_data_migration.mdx +++ b/api_docs/cloud_data_migration.mdx @@ -8,14 +8,14 @@ slug: /kibana-dev-docs/api/cloudDataMigration title: "cloudDataMigration" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudDataMigration plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudDataMigration'] --- import cloudDataMigrationObj from './cloud_data_migration.devdocs.json'; Static migration page where self-managed users can see text/copy about migrating to Elastic Cloud -Contact [@elastic/platform-onboarding](https://github.com/orgs/elastic/teams/platform-onboarding) for questions regarding this plugin. +Contact [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) for questions regarding this plugin. **Code health stats** diff --git a/api_docs/cloud_defend.mdx b/api_docs/cloud_defend.mdx index 8de28a174848f..24544c722e6dd 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudDefend'] --- import cloudDefendObj from './cloud_defend.devdocs.json'; diff --git a/api_docs/cloud_experiments.mdx b/api_docs/cloud_experiments.mdx index e6e64081f4816..396b903198da9 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-05-20 +date: 2024-05-23 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 d3be4f1ecfc58..1437a4aeed3fe 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-05-20 +date: 2024-05-23 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 c8c436075e006..ece66ab72b14f 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-05-20 +date: 2024-05-23 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 3d97d8d324d82..80b89b07b34ac 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-05-20 +date: 2024-05-23 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 4bb2d4f5b695e..0a9aef618077a 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-05-20 +date: 2024-05-23 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 d20c0d817bad2..27e8f8e5bdac2 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-05-20 +date: 2024-05-23 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 ebc2ca136d543..d5ed5074da484 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-05-20 +date: 2024-05-23 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 ed8a799c2e890..541b8dc3ad97e 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-05-20 +date: 2024-05-23 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 1a5d1f793c624..df9d6194ad15e 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data'] --- import dataObj from './data.devdocs.json'; diff --git a/api_docs/data_query.mdx b/api_docs/data_query.mdx index 72ec9098d970b..5053eadcdfd8e 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.query'] --- import dataQueryObj from './data_query.devdocs.json'; diff --git a/api_docs/data_search.mdx b/api_docs/data_search.mdx index f9e1313b825b5..c2fffa99ffe22 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-05-20 +date: 2024-05-23 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 e14fbb84c8c3e..d5c43edf26e00 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-05-20 +date: 2024-05-23 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 47f679b648687..3b13f0a70138f 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-05-20 +date: 2024-05-23 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 dc854eb2bc307..f7dacb5a257b9 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-05-20 +date: 2024-05-23 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 be2d13723e34b..2c09281170e7b 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-05-20 +date: 2024-05-23 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 0ce9929024c75..2aaf351a81d2c 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-05-20 +date: 2024-05-23 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 5cc8ac5c6b11b..7ecba86d48d94 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-05-20 +date: 2024-05-23 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 7fdfb650df82d..742647dd1a323 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index 18390038fa500..bcfe75c192a43 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/deprecations_by_team.mdx b/api_docs/deprecations_by_team.mdx index 919da7d93a174..9c6e44cb653e5 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/dev_tools.mdx b/api_docs/dev_tools.mdx index fe61ae6d29a50..97506496eb198 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-05-20 +date: 2024-05-23 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 14de89d8f6e4b..5695f2c0a6a06 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-05-20 +date: 2024-05-23 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 653c09fe0385f..37e0f950fcf39 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-05-20 +date: 2024-05-23 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 97c75e0d7949e..6e9d1dad814aa 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-05-20 +date: 2024-05-23 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 4c6d8f24223ab..4f007ef54be2f 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-05-20 +date: 2024-05-23 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 305f009d109af..73d9cc8d736fc 100644 --- a/api_docs/elastic_assistant.devdocs.json +++ b/api_docs/elastic_assistant.devdocs.json @@ -1494,6 +1494,8 @@ "ActionsClientLlm", " | ", "ActionsClientChatOpenAI", + " | ", + "ActionsClientSimpleChatModel", " | undefined" ], "path": "x-pack/plugins/elastic_assistant/server/types.ts", diff --git a/api_docs/elastic_assistant.mdx b/api_docs/elastic_assistant.mdx index c1d9e7f1f3dab..f4e8a0abd680f 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'elasticAssistant'] --- import elasticAssistantObj from './elastic_assistant.devdocs.json'; diff --git a/api_docs/embeddable.devdocs.json b/api_docs/embeddable.devdocs.json index 24e5f07f0453a..1322b23c1e5da 100644 --- a/api_docs/embeddable.devdocs.json +++ b/api_docs/embeddable.devdocs.json @@ -443,37 +443,6 @@ "deprecated": false, "trackAdoption": false }, - { - "parentPluginId": "embeddable", - "id": "def-public.Container.lastSavedState", - "type": "Object", - "tags": [], - "label": "lastSavedState", - "description": [], - "signature": [ - "Subject", - "" - ], - "path": "src/plugins/embeddable/public/lib/containers/container.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "embeddable", - "id": "def-public.Container.getLastSavedStateForChild", - "type": "Function", - "tags": [], - "label": "getLastSavedStateForChild", - "description": [], - "signature": [ - "() => undefined" - ], - "path": "src/plugins/embeddable/public/lib/containers/container.ts", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] - }, { "parentPluginId": "embeddable", "id": "def-public.Container.Unnamed", @@ -8929,7 +8898,7 @@ "\nRenders a component from the React Embeddable registry into a Presentation Panel.\n\nTODO: Rename this to simply `Embeddable` when the legacy Embeddable system is removed." ], "signature": [ - " = ", + " = ", { "pluginId": "embeddable", "scope": "public", @@ -8945,15 +8914,23 @@ "section": "def-public.DefaultEmbeddableApi", "text": "DefaultEmbeddableApi" }, - ">({ maybeId, type, state, parentApi, onApiAvailable, panelProps, onAnyStateChange, hidePanelChrome, }: { maybeId?: string | undefined; type: string; state: ", + ", RuntimeState extends object = SerializedState, ParentApi extends ", { "pluginId": "@kbn/presentation-containers", "scope": "common", "docId": "kibKbnPresentationContainersPluginApi", - "section": "def-common.SerializedPanelState", - "text": "SerializedPanelState" + "section": "def-common.HasSerializedChildState", + "text": "HasSerializedChildState" }, - "; parentApi?: unknown; onApiAvailable?: ((api: ApiType) => void) | undefined; panelProps?: Pick<", + " = ", + { + "pluginId": "@kbn/presentation-containers", + "scope": "common", + "docId": "kibKbnPresentationContainersPluginApi", + "section": "def-common.HasSerializedChildState", + "text": "HasSerializedChildState" + }, + ">({ type, maybeId, getParentApi, panelProps, onAnyStateChange, onApiAvailable, hidePanelChrome, }: { type: string; maybeId?: string | undefined; getParentApi: () => ParentApi; onApiAvailable?: ((api: Api) => void) | undefined; panelProps?: Pick<", { "pluginId": "presentationPanel", "scope": "public", @@ -8961,7 +8938,7 @@ "section": "def-public.PresentationPanelProps", "text": "PresentationPanelProps" }, - ", \"showShadow\" | \"showBorder\" | \"showBadges\" | \"showNotifications\" | \"hideHeader\" | \"hideInspector\"> | undefined; hidePanelChrome?: boolean | undefined; onAnyStateChange?: ((state: ", + ", \"showShadow\" | \"showBorder\" | \"showBadges\" | \"showNotifications\" | \"hideHeader\" | \"hideInspector\"> | undefined; hidePanelChrome?: boolean | undefined; onAnyStateChange?: ((state: ", { "pluginId": "@kbn/presentation-containers", "scope": "common", @@ -8969,7 +8946,7 @@ "section": "def-common.SerializedPanelState", "text": "SerializedPanelState" }, - ") => void) | undefined; }) => JSX.Element" + ") => void) | undefined; }) => JSX.Element" ], "path": "src/plugins/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx", "deprecated": false, @@ -8980,26 +8957,12 @@ "id": "def-public.ReactEmbeddableRenderer.$1", "type": "Object", "tags": [], - "label": "{\n maybeId,\n type,\n state,\n parentApi,\n onApiAvailable,\n panelProps,\n onAnyStateChange,\n hidePanelChrome,\n}", + "label": "{\n type,\n maybeId,\n getParentApi,\n panelProps,\n onAnyStateChange,\n onApiAvailable,\n hidePanelChrome,\n}", "description": [], "path": "src/plugins/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx", "deprecated": false, "trackAdoption": false, "children": [ - { - "parentPluginId": "embeddable", - "id": "def-public.ReactEmbeddableRenderer.$1.maybeId", - "type": "string", - "tags": [], - "label": "maybeId", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "src/plugins/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx", - "deprecated": false, - "trackAdoption": false - }, { "parentPluginId": "embeddable", "id": "def-public.ReactEmbeddableRenderer.$1.type", @@ -9013,20 +8976,13 @@ }, { "parentPluginId": "embeddable", - "id": "def-public.ReactEmbeddableRenderer.$1.state", - "type": "Object", + "id": "def-public.ReactEmbeddableRenderer.$1.maybeId", + "type": "string", "tags": [], - "label": "state", + "label": "maybeId", "description": [], "signature": [ - { - "pluginId": "@kbn/presentation-containers", - "scope": "common", - "docId": "kibKbnPresentationContainersPluginApi", - "section": "def-common.SerializedPanelState", - "text": "SerializedPanelState" - }, - "" + "string | undefined" ], "path": "src/plugins/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx", "deprecated": false, @@ -9034,17 +8990,19 @@ }, { "parentPluginId": "embeddable", - "id": "def-public.ReactEmbeddableRenderer.$1.parentApi", - "type": "Unknown", + "id": "def-public.ReactEmbeddableRenderer.$1.getParentApi", + "type": "Function", "tags": [], - "label": "parentApi", + "label": "getParentApi", "description": [], "signature": [ - "unknown" + "() => ParentApi" ], "path": "src/plugins/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx", "deprecated": false, - "trackAdoption": false + "trackAdoption": false, + "children": [], + "returnComment": [] }, { "parentPluginId": "embeddable", @@ -9054,7 +9012,7 @@ "label": "onApiAvailable", "description": [], "signature": [ - "((api: ApiType) => void) | undefined" + "((api: Api) => void) | undefined" ], "path": "src/plugins/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx", "deprecated": false, @@ -9068,7 +9026,7 @@ "label": "api", "description": [], "signature": [ - "ApiType" + "Api" ], "path": "src/plugins/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx", "deprecated": false, @@ -9094,7 +9052,7 @@ "section": "def-public.PresentationPanelProps", "text": "PresentationPanelProps" }, - ", \"showShadow\" | \"showBorder\" | \"showBadges\" | \"showNotifications\" | \"hideHeader\" | \"hideInspector\"> | undefined" + ", \"showShadow\" | \"showBorder\" | \"showBadges\" | \"showNotifications\" | \"hideHeader\" | \"hideInspector\"> | undefined" ], "path": "src/plugins/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx", "deprecated": false, @@ -9132,7 +9090,7 @@ "section": "def-common.SerializedPanelState", "text": "SerializedPanelState" }, - ") => void) | undefined" + ") => void) | undefined" ], "path": "src/plugins/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx", "deprecated": false, @@ -9153,7 +9111,7 @@ "section": "def-common.SerializedPanelState", "text": "SerializedPanelState" }, - "" + "" ], "path": "src/plugins/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx", "deprecated": false, @@ -9349,119 +9307,6 @@ "returnComment": [], "initialIsOpen": false }, - { - "parentPluginId": "embeddable", - "id": "def-public.startTrackingEmbeddableUnsavedChanges", - "type": "Function", - "tags": [], - "label": "startTrackingEmbeddableUnsavedChanges", - "description": [], - "signature": [ - "(uuid: string, parentApi: unknown, comparators: ", - { - "pluginId": "@kbn/presentation-publishing", - "scope": "common", - "docId": "kibKbnPresentationPublishingPluginApi", - "section": "def-common.StateComparators", - "text": "StateComparators" - }, - ", deserializeState: (state: ", - { - "pluginId": "@kbn/presentation-containers", - "scope": "common", - "docId": "kibKbnPresentationContainersPluginApi", - "section": "def-common.SerializedPanelState", - "text": "SerializedPanelState" - }, - ") => RuntimeState) => { unsavedChanges: ", - "BehaviorSubject", - "; resetUnsavedChanges: () => void; cleanup: () => void; } | { unsavedChanges: ", - "BehaviorSubject", - " | undefined>; resetUnsavedChanges: () => void; cleanup: () => void; }" - ], - "path": "src/plugins/embeddable/public/react_embeddable_system/react_embeddable_unsaved_changes.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "embeddable", - "id": "def-public.startTrackingEmbeddableUnsavedChanges.$1", - "type": "string", - "tags": [], - "label": "uuid", - "description": [], - "signature": [ - "string" - ], - "path": "src/plugins/embeddable/public/react_embeddable_system/react_embeddable_unsaved_changes.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "embeddable", - "id": "def-public.startTrackingEmbeddableUnsavedChanges.$2", - "type": "Unknown", - "tags": [], - "label": "parentApi", - "description": [], - "signature": [ - "unknown" - ], - "path": "src/plugins/embeddable/public/react_embeddable_system/react_embeddable_unsaved_changes.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "embeddable", - "id": "def-public.startTrackingEmbeddableUnsavedChanges.$3", - "type": "Object", - "tags": [], - "label": "comparators", - "description": [], - "signature": [ - { - "pluginId": "@kbn/presentation-publishing", - "scope": "common", - "docId": "kibKbnPresentationPublishingPluginApi", - "section": "def-common.StateComparators", - "text": "StateComparators" - }, - "" - ], - "path": "src/plugins/embeddable/public/react_embeddable_system/react_embeddable_unsaved_changes.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "embeddable", - "id": "def-public.startTrackingEmbeddableUnsavedChanges.$4", - "type": "Function", - "tags": [], - "label": "deserializeState", - "description": [], - "signature": [ - "(state: ", - { - "pluginId": "@kbn/presentation-containers", - "scope": "common", - "docId": "kibKbnPresentationContainersPluginApi", - "section": "def-common.SerializedPanelState", - "text": "SerializedPanelState" - }, - ") => RuntimeState" - ], - "path": "src/plugins/embeddable/public/react_embeddable_system/react_embeddable_unsaved_changes.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - }, { "parentPluginId": "embeddable", "id": "def-public.useEmbeddableFactory", @@ -9774,7 +9619,7 @@ "section": "def-public.DefaultEmbeddableApi", "text": "DefaultEmbeddableApi" }, - " extends ", + " extends ", "DefaultPresentationPanelApi", ",", { @@ -9800,7 +9645,15 @@ "section": "def-common.HasSerializableState", "text": "HasSerializableState" }, - "" + ",", + { + "pluginId": "@kbn/presentation-containers", + "scope": "common", + "docId": "kibKbnPresentationContainersPluginApi", + "section": "def-common.HasSnapshottableState", + "text": "HasSnapshottableState" + }, + "" ], "path": "src/plugins/embeddable/public/react_embeddable_system/types.ts", "deprecated": false, @@ -12887,7 +12740,7 @@ "section": "def-public.ReactEmbeddableFactory", "text": "ReactEmbeddableFactory" }, - "" + "" ], "path": "src/plugins/embeddable/public/react_embeddable_system/types.ts", "deprecated": false, @@ -12913,10 +12766,10 @@ "tags": [], "label": "deserializeState", "description": [ - "\nA required synchronous function that transforms serialized state into runtime state.\nThis will be used twice - once for the parent state, and once for the last saved state\nfor comparison.\n\nThis can also be used to:\n\n- Inject references provided by the parent\n- Migrate the state to a newer version (this must be undone when serializing)" + "\nA required asynchronous function that transforms serialized state into runtime state.\n\nThis could be used to:\n- Load state from some external store\n- Inject references provided by the parent\n- Migrate the state to a newer version (this must be undone when serializing)" ], "signature": [ - "(state: ", + "(panelState: ", { "pluginId": "@kbn/presentation-containers", "scope": "common", @@ -12924,7 +12777,15 @@ "section": "def-common.SerializedPanelState", "text": "SerializedPanelState" }, - ") => RuntimeState" + ") => ", + { + "pluginId": "@kbn/utility-types", + "scope": "common", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-common.MaybePromise", + "text": "MaybePromise" + }, + "" ], "path": "src/plugins/embeddable/public/react_embeddable_system/types.ts", "deprecated": false, @@ -12935,7 +12796,7 @@ "id": "def-public.ReactEmbeddableFactory.deserializeState.$1", "type": "Object", "tags": [], - "label": "state", + "label": "panelState", "description": [], "signature": [ { @@ -12967,7 +12828,7 @@ "signature": [ "(initialState: RuntimeState, buildApi: (apiRegistration: ", "ReactEmbeddableApiRegistration", - ", comparators: ", + ", comparators: ", { "pluginId": "@kbn/presentation-publishing", "scope": "common", @@ -12975,7 +12836,7 @@ "section": "def-common.StateComparators", "text": "StateComparators" }, - ") => ApiType, uuid: string, parentApi?: unknown) => Promise<{ Component: React.FC<{}>; api: ApiType; }>" + ") => Api, uuid: string, parentApi?: unknown) => Promise<{ Component: React.FC<{}>; api: Api; }>" ], "path": "src/plugins/embeddable/public/react_embeddable_system/types.ts", "deprecated": false, @@ -13006,7 +12867,7 @@ "signature": [ "(apiRegistration: ", "ReactEmbeddableApiRegistration", - ", comparators: ", + ", comparators: ", { "pluginId": "@kbn/presentation-publishing", "scope": "common", @@ -13014,7 +12875,7 @@ "section": "def-common.StateComparators", "text": "StateComparators" }, - ") => ApiType" + ") => Api" ], "path": "src/plugins/embeddable/public/react_embeddable_system/types.ts", "deprecated": false, @@ -13586,38 +13447,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "embeddable", - "id": "def-public.ReactEmbeddableRegistration", - "type": "Type", - "tags": [], - "label": "ReactEmbeddableRegistration", - "description": [], - "signature": [ - "(ref: React.ForwardedRef) => React.ReactElement> | null" - ], - "path": "src/plugins/embeddable/public/react_embeddable_system/types.ts", - "deprecated": false, - "trackAdoption": false, - "returnComment": [], - "children": [ - { - "parentPluginId": "embeddable", - "id": "def-public.ReactEmbeddableRegistration.$1", - "type": "CompoundType", - "tags": [], - "label": "ref", - "description": [], - "signature": [ - "((instance: ApiType | null) => void) | React.MutableRefObject | null" - ], - "path": "src/plugins/embeddable/public/react_embeddable_system/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, { "parentPluginId": "embeddable", "id": "def-public.ReactEmbeddableSavedObject", @@ -14197,7 +14026,7 @@ "\nRegisters an async {@link ReactEmbeddableFactory} getter." ], "signature": [ - " = ", + " = ", { "pluginId": "embeddable", "scope": "public", @@ -14213,7 +14042,7 @@ "section": "def-public.DefaultEmbeddableApi", "text": "DefaultEmbeddableApi" }, - ">(type: string, getFactory: () => Promise<", + ", RuntimeState extends object = SerializedState>(type: string, getFactory: () => Promise<", { "pluginId": "embeddable", "scope": "public", @@ -14221,11 +14050,12 @@ "section": "def-public.ReactEmbeddableFactory", "text": "ReactEmbeddableFactory" }, - ">) => void" + ">) => void" ], "path": "src/plugins/embeddable/public/plugin.tsx", "deprecated": false, "trackAdoption": false, + "returnComment": [], "children": [ { "parentPluginId": "embeddable", @@ -14234,13 +14064,9 @@ "tags": [], "label": "type", "description": [], - "signature": [ - "string" - ], - "path": "src/plugins/embeddable/public/plugin.tsx", + "path": "src/plugins/embeddable/public/react_embeddable_system/react_embeddable_registry.ts", "deprecated": false, - "trackAdoption": false, - "isRequired": true + "trackAdoption": false }, { "parentPluginId": "embeddable", @@ -14258,15 +14084,15 @@ "section": "def-public.ReactEmbeddableFactory", "text": "ReactEmbeddableFactory" }, - ">" + ">" ], - "path": "src/plugins/embeddable/public/plugin.tsx", + "path": "src/plugins/embeddable/public/react_embeddable_system/react_embeddable_registry.ts", "deprecated": false, "trackAdoption": false, - "isRequired": true + "returnComment": [], + "children": [] } - ], - "returnComment": [] + ] }, { "parentPluginId": "embeddable", diff --git a/api_docs/embeddable.mdx b/api_docs/embeddable.mdx index 757f36c217e31..dab398865b598 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'embeddable'] --- import embeddableObj from './embeddable.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kib | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 564 | 1 | 454 | 8 | +| 554 | 1 | 444 | 8 | ## Client diff --git a/api_docs/embeddable_enhanced.mdx b/api_docs/embeddable_enhanced.mdx index 3bd9e45fbb55f..78d1141c7d27b 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-05-20 +date: 2024-05-23 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 0f027d6476aab..0d0dd76dc9c72 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-05-20 +date: 2024-05-23 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 df612f3ba58c0..f6d4abe9e424e 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'enterpriseSearch'] --- import enterpriseSearchObj from './enterprise_search.devdocs.json'; diff --git a/api_docs/es_ui_shared.mdx b/api_docs/es_ui_shared.mdx index bfbce14d2f28a..b68e8b99b6b0c 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esUiShared'] --- import esUiSharedObj from './es_ui_shared.devdocs.json'; diff --git a/api_docs/event_annotation.mdx b/api_docs/event_annotation.mdx index a143a6710e4fa..fd0b7162cc4ab 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-05-20 +date: 2024-05-23 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 6305e112cb763..7d8b2b2845ff7 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-05-20 +date: 2024-05-23 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 67bf2d55c88ca..1ab3b086d46bf 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-05-20 +date: 2024-05-23 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 ea5ad4f14611c..7c7d28af8418b 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-05-20 +date: 2024-05-23 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 13ddadc0355f1..0c7fbefee4dcc 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-05-20 +date: 2024-05-23 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 7b7e8b16fe3d9..5e374ed606af2 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-05-20 +date: 2024-05-23 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 36a025e989bd6..c9fd6d22f3e93 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-05-20 +date: 2024-05-23 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 2ed037401a5ee..b88405e30fc74 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-05-20 +date: 2024-05-23 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 0a2f7f52ae824..1674e24e32158 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-05-20 +date: 2024-05-23 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 de0d33b3fe139..49e444f780bd9 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-05-20 +date: 2024-05-23 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 81552f2a71390..7da9b62ed83c0 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-05-20 +date: 2024-05-23 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 0d361a1ef6ee5..836638bc5d49f 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-05-20 +date: 2024-05-23 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 3221b1bc91391..9c48c2f591364 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-05-20 +date: 2024-05-23 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 c41d008ceab6d..83aecbc96eba9 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-05-20 +date: 2024-05-23 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 857bb8256b2ec..417738b227f66 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-05-20 +date: 2024-05-23 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 36feeaee47c02..29e6d0e594430 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-05-20 +date: 2024-05-23 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 9a90063d9957a..32bc1e23d485f 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-05-20 +date: 2024-05-23 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 550863a9a75e6..9f91694efe0cf 100644 --- a/api_docs/expressions.devdocs.json +++ b/api_docs/expressions.devdocs.json @@ -270,6 +270,23 @@ "deprecated": false, "trackAdoption": false, "isRequired": false + }, + { + "parentPluginId": "expressions", + "id": "def-public.Execution.Unnamed.$3", + "type": "Object", + "tags": [], + "label": "functionCache", + "description": [], + "signature": [ + "Map" + ], + "path": "src/plugins/expressions/common/execution/execution.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true } ], "returnComment": [] @@ -1271,6 +1288,23 @@ "deprecated": false, "trackAdoption": false, "isRequired": false + }, + { + "parentPluginId": "expressions", + "id": "def-public.Executor.Unnamed.$3", + "type": "Object", + "tags": [], + "label": "functionCache", + "description": [], + "signature": [ + "Map" + ], + "path": "src/plugins/expressions/common/executor/executor.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true } ], "returnComment": [] @@ -2197,6 +2231,19 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "expressions", + "id": "def-public.ExpressionFunction.allowCache", + "type": "boolean", + "tags": [], + "label": "allowCache", + "description": [ + "\nOpt-in to caching this function. By default function outputs are cached and given the same inputs cached result is returned." + ], + "path": "src/plugins/expressions/common/expression_functions/expression_function.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "expressions", "id": "def-public.ExpressionFunction.fn", @@ -7146,6 +7193,22 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "expressions", + "id": "def-public.ExecutionContext.allowCache", + "type": "CompoundType", + "tags": [], + "label": "allowCache", + "description": [ + "\nAllow caching in the current execution." + ], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/expressions/common/execution/types.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "expressions", "id": "def-public.ExecutionContext.abortSignal", @@ -8383,6 +8446,22 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "expressions", + "id": "def-public.ExpressionFunctionDefinition.allowCache", + "type": "CompoundType", + "tags": [], + "label": "allowCache", + "description": [ + "\nOpt-in to caching this function. By default function outputs are cached and given the same inputs cached result is returned." + ], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/expressions/common/expression_functions/types.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "expressions", "id": "def-public.ExpressionFunctionDefinition.inputTypes", @@ -10726,20 +10805,6 @@ "deprecated": false, "trackAdoption": false }, - { - "parentPluginId": "expressions", - "id": "def-public.IExpressionLoaderParams.disableCaching", - "type": "CompoundType", - "tags": [], - "label": "disableCaching", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "src/plugins/expressions/public/types/index.ts", - "deprecated": false, - "trackAdoption": false - }, { "parentPluginId": "expressions", "id": "def-public.IExpressionLoaderParams.customFunctions", @@ -11011,6 +11076,20 @@ "path": "src/plugins/expressions/public/types/index.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "expressions", + "id": "def-public.IExpressionLoaderParams.allowCache", + "type": "CompoundType", + "tags": [], + "label": "allowCache", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/expressions/public/types/index.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -13813,6 +13892,23 @@ "deprecated": false, "trackAdoption": false, "isRequired": false + }, + { + "parentPluginId": "expressions", + "id": "def-server.Execution.Unnamed.$3", + "type": "Object", + "tags": [], + "label": "functionCache", + "description": [], + "signature": [ + "Map" + ], + "path": "src/plugins/expressions/common/execution/execution.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true } ], "returnComment": [] @@ -14595,6 +14691,23 @@ "deprecated": false, "trackAdoption": false, "isRequired": false + }, + { + "parentPluginId": "expressions", + "id": "def-server.Executor.Unnamed.$3", + "type": "Object", + "tags": [], + "label": "functionCache", + "description": [], + "signature": [ + "Map" + ], + "path": "src/plugins/expressions/common/executor/executor.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true } ], "returnComment": [] @@ -15521,6 +15634,19 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "expressions", + "id": "def-server.ExpressionFunction.allowCache", + "type": "boolean", + "tags": [], + "label": "allowCache", + "description": [ + "\nOpt-in to caching this function. By default function outputs are cached and given the same inputs cached result is returned." + ], + "path": "src/plugins/expressions/common/expression_functions/expression_function.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "expressions", "id": "def-server.ExpressionFunction.fn", @@ -18575,6 +18701,22 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "expressions", + "id": "def-server.ExecutionContext.allowCache", + "type": "CompoundType", + "tags": [], + "label": "allowCache", + "description": [ + "\nAllow caching in the current execution." + ], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/expressions/common/execution/types.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "expressions", "id": "def-server.ExecutionContext.abortSignal", @@ -19781,6 +19923,22 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "expressions", + "id": "def-server.ExpressionFunctionDefinition.allowCache", + "type": "CompoundType", + "tags": [], + "label": "allowCache", + "description": [ + "\nOpt-in to caching this function. By default function outputs are cached and given the same inputs cached result is returned." + ], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/expressions/common/expression_functions/types.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "expressions", "id": "def-server.ExpressionFunctionDefinition.inputTypes", @@ -22974,6 +23132,23 @@ "deprecated": false, "trackAdoption": false, "isRequired": false + }, + { + "parentPluginId": "expressions", + "id": "def-common.Execution.Unnamed.$3", + "type": "Object", + "tags": [], + "label": "functionCache", + "description": [], + "signature": [ + "Map" + ], + "path": "src/plugins/expressions/common/execution/execution.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true } ], "returnComment": [] @@ -23975,6 +24150,23 @@ "deprecated": false, "trackAdoption": false, "isRequired": false + }, + { + "parentPluginId": "expressions", + "id": "def-common.Executor.Unnamed.$3", + "type": "Object", + "tags": [], + "label": "functionCache", + "description": [], + "signature": [ + "Map" + ], + "path": "src/plugins/expressions/common/executor/executor.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true } ], "returnComment": [] @@ -24901,6 +25093,19 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "expressions", + "id": "def-common.ExpressionFunction.allowCache", + "type": "boolean", + "tags": [], + "label": "allowCache", + "description": [ + "\nOpt-in to caching this function. By default function outputs are cached and given the same inputs cached result is returned." + ], + "path": "src/plugins/expressions/common/expression_functions/expression_function.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "expressions", "id": "def-common.ExpressionFunction.fn", @@ -30648,6 +30853,22 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "expressions", + "id": "def-common.ExecutionContext.allowCache", + "type": "CompoundType", + "tags": [], + "label": "allowCache", + "description": [ + "\nAllow caching in the current execution." + ], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/expressions/common/execution/types.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "expressions", "id": "def-common.ExecutionContext.abortSignal", @@ -32523,6 +32744,20 @@ "path": "src/plugins/expressions/common/service/expressions_services.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "expressions", + "id": "def-common.ExpressionExecutionParams.allowCache", + "type": "CompoundType", + "tags": [], + "label": "allowCache", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/expressions/common/service/expressions_services.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -32675,6 +32910,22 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "expressions", + "id": "def-common.ExpressionFunctionDefinition.allowCache", + "type": "CompoundType", + "tags": [], + "label": "allowCache", + "description": [ + "\nOpt-in to caching this function. By default function outputs are cached and given the same inputs cached result is returned." + ], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/expressions/common/expression_functions/types.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "expressions", "id": "def-common.ExpressionFunctionDefinition.inputTypes", diff --git a/api_docs/expressions.mdx b/api_docs/expressions.mdx index 8e952fd651860..91239461772dd 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-05-20 +date: 2024-05-23 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 | |-------------------|-----------|------------------------|-----------------| -| 2217 | 17 | 1756 | 5 | +| 2233 | 17 | 1763 | 6 | ## Client diff --git a/api_docs/features.mdx b/api_docs/features.mdx index e06c1d1c23064..d101b67054720 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-05-20 +date: 2024-05-23 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 a693e34dcd748..ee43da5aca400 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fieldFormats'] --- import fieldFormatsObj from './field_formats.devdocs.json'; diff --git a/api_docs/file_upload.mdx b/api_docs/file_upload.mdx index 870212a3293ee..1b64a42c70dcb 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-05-20 +date: 2024-05-23 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 7bb838c05c90f..b01ac24462c2c 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-05-20 +date: 2024-05-23 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 ac9ae8788cf90..56b31af498db5 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-05-20 +date: 2024-05-23 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 9767c0c9487f8..cc485026a9c3e 100644 --- a/api_docs/fleet.devdocs.json +++ b/api_docs/fleet.devdocs.json @@ -23690,6 +23690,20 @@ "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "fleet", + "id": "def-common.PackagePolicyPackage.requires_root", + "type": "CompoundType", + "tags": [], + "label": "requires_root", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -27389,6 +27403,17 @@ "path": "x-pack/plugins/fleet/common/constants/routes.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "fleet", + "id": "def-common.AGENT_API_ROUTES.DELETE_UPLOAD_FILE_PATTERN", + "type": "string", + "tags": [], + "label": "DELETE_UPLOAD_FILE_PATTERN", + "description": [], + "path": "x-pack/plugins/fleet/common/constants/routes.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -28361,6 +28386,38 @@ ], "returnComment": [] }, + { + "parentPluginId": "fleet", + "id": "def-common.agentRouteService.getAgentFileDeletePath", + "type": "Function", + "tags": [], + "label": "getAgentFileDeletePath", + "description": [], + "signature": [ + "(fileId: string) => string" + ], + "path": "x-pack/plugins/fleet/common/services/routes.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "fleet", + "id": "def-common.agentRouteService.getAgentFileDeletePath.$1", + "type": "string", + "tags": [], + "label": "fileId", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/fleet/common/services/routes.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, { "parentPluginId": "fleet", "id": "def-common.agentRouteService.getAgentsByActionsPath", diff --git a/api_docs/fleet.mdx b/api_docs/fleet.mdx index 75ac3909b9408..0544bdb3a512c 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-05-20 +date: 2024-05-23 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 | |-------------------|-----------|------------------------|-----------------| -| 1305 | 5 | 1184 | 66 | +| 1309 | 5 | 1188 | 66 | ## Client diff --git a/api_docs/global_search.mdx b/api_docs/global_search.mdx index ee0269cb007a6..4d6bfd6455534 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-05-20 +date: 2024-05-23 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 3541f8296b9b6..d2c00e70b9a0a 100644 --- a/api_docs/guided_onboarding.mdx +++ b/api_docs/guided_onboarding.mdx @@ -8,14 +8,14 @@ slug: /kibana-dev-docs/api/guidedOnboarding title: "guidedOnboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the guidedOnboarding plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'guidedOnboarding'] --- import guidedOnboardingObj from './guided_onboarding.devdocs.json'; Guided onboarding framework -Contact [@elastic/platform-onboarding](https://github.com/orgs/elastic/teams/platform-onboarding) for questions regarding this plugin. +Contact [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) for questions regarding this plugin. **Code health stats** diff --git a/api_docs/home.mdx b/api_docs/home.mdx index 8f14b511df193..a7f1ffcc015cb 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-05-20 +date: 2024-05-23 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 5f558f384c873..25677b0d4e9f5 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-05-20 +date: 2024-05-23 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 3f71772224b12..87929c36d5fd6 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexLifecycleManagement'] --- import indexLifecycleManagementObj from './index_lifecycle_management.devdocs.json'; diff --git a/api_docs/index_management.mdx b/api_docs/index_management.mdx index ac72aa6d904f7..bee874af3f73b 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-05-20 +date: 2024-05-23 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 d85f5f4552cb1..0260ea5c4238a 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-05-20 +date: 2024-05-23 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 a72b9a6905658..50b7b1db755b9 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-05-20 +date: 2024-05-23 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 ce43a012265d9..40030cc86eebc 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inspector'] --- import inspectorObj from './inspector.devdocs.json'; diff --git a/api_docs/interactive_setup.mdx b/api_docs/interactive_setup.mdx index 5d01194336435..dc7fe8b75cc46 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'interactiveSetup'] --- import interactiveSetupObj from './interactive_setup.devdocs.json'; diff --git a/api_docs/kbn_ace.mdx b/api_docs/kbn_ace.mdx index 75116cba2206b..af891fc6ca921 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ace'] --- import kbnAceObj from './kbn_ace.devdocs.json'; diff --git a/api_docs/kbn_actions_types.mdx b/api_docs/kbn_actions_types.mdx index 2218cc06aec6f..0ebfc6f06e7a0 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/actions-types'] --- import kbnActionsTypesObj from './kbn_actions_types.devdocs.json'; diff --git a/api_docs/kbn_aiops_components.mdx b/api_docs/kbn_aiops_components.mdx index 37b1ce851614a..5722bd3344924 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-05-20 +date: 2024-05-23 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 6d2d3f466d0b7..5cbf06bd4084f 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-05-20 +date: 2024-05-23 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 a244910fe2af8..102f040638267 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-05-20 +date: 2024-05-23 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 bd3e35c910950..2d28ad61ce1a9 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-05-20 +date: 2024-05-23 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_state_types.mdx b/api_docs/kbn_alerting_state_types.mdx index f8a768273a666..d6c0a85aabd3a 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-05-20 +date: 2024-05-23 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 f69d8259e7554..4da914b5f4b0d 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-05-20 +date: 2024-05-23 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 a40a003ea3ad4..8908cef1fd3ed 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-as-data-utils'] --- import kbnAlertsAsDataUtilsObj from './kbn_alerts_as_data_utils.devdocs.json'; diff --git a/api_docs/kbn_alerts_ui_shared.mdx b/api_docs/kbn_alerts_ui_shared.mdx index 0ceaddc5d97c6..f393d9dbf1b5d 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-ui-shared'] --- import kbnAlertsUiSharedObj from './kbn_alerts_ui_shared.devdocs.json'; diff --git a/api_docs/kbn_analytics.mdx b/api_docs/kbn_analytics.mdx index e6d44f5fc12af..07925dcc54a05 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics'] --- import kbnAnalyticsObj from './kbn_analytics.devdocs.json'; diff --git a/api_docs/kbn_analytics_client.devdocs.json b/api_docs/kbn_analytics_client.devdocs.json index 02f60c3586d6b..44ac84f58b11d 100644 --- a/api_docs/kbn_analytics_client.devdocs.json +++ b/api_docs/kbn_analytics_client.devdocs.json @@ -826,6 +826,10 @@ "plugin": "infra", "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts" + }, { "plugin": "osquery", "path": "x-pack/plugins/osquery/server/lib/telemetry/sender.ts" @@ -1166,6 +1170,14 @@ "plugin": "infra", "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_service.test.ts" diff --git a/api_docs/kbn_analytics_client.mdx b/api_docs/kbn_analytics_client.mdx index 11475be46c8e8..cb70cef0b091e 100644 --- a/api_docs/kbn_analytics_client.mdx +++ b/api_docs/kbn_analytics_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-client title: "@kbn/analytics-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-client plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-client'] --- import kbnAnalyticsClientObj from './kbn_analytics_client.devdocs.json'; diff --git a/api_docs/kbn_analytics_collection_utils.mdx b/api_docs/kbn_analytics_collection_utils.mdx index a63f4e6cc0ff2..3ab963549874d 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-collection-utils'] --- import kbnAnalyticsCollectionUtilsObj from './kbn_analytics_collection_utils.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx index 7d57f62f66383..9996c76e5b5af 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-browser title: "@kbn/analytics-shippers-elastic-v3-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-browser plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-browser'] --- import kbnAnalyticsShippersElasticV3BrowserObj from './kbn_analytics_shippers_elastic_v3_browser.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx index 2454fb1be5b45..8efd4e83e1bf8 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-common title: "@kbn/analytics-shippers-elastic-v3-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-common plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-common'] --- import kbnAnalyticsShippersElasticV3CommonObj from './kbn_analytics_shippers_elastic_v3_common.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx index 3a6988d2f1083..76b7aeca66363 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-server title: "@kbn/analytics-shippers-elastic-v3-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-server plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-server'] --- import kbnAnalyticsShippersElasticV3ServerObj from './kbn_analytics_shippers_elastic_v3_server.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_fullstory.mdx b/api_docs/kbn_analytics_shippers_fullstory.mdx index 2194b53b01c67..45e20adde7d88 100644 --- a/api_docs/kbn_analytics_shippers_fullstory.mdx +++ b/api_docs/kbn_analytics_shippers_fullstory.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-fullstory title: "@kbn/analytics-shippers-fullstory" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-fullstory plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-fullstory'] --- import kbnAnalyticsShippersFullstoryObj from './kbn_analytics_shippers_fullstory.devdocs.json'; diff --git a/api_docs/kbn_apm_config_loader.mdx b/api_docs/kbn_apm_config_loader.mdx index d24056e55af3a..d23cbd9234249 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-05-20 +date: 2024-05-23 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 4ebcfcea51128..d5f7017ea3cef 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-05-20 +date: 2024-05-23 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 5a2b271647f7a..215295a77de55 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-05-20 +date: 2024-05-23 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 33a7e8454d362..0dc186eb521fc 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-05-20 +date: 2024-05-23 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 b8771eaff3bb9..5a871183213be 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-utils'] --- import kbnApmUtilsObj from './kbn_apm_utils.devdocs.json'; diff --git a/api_docs/kbn_axe_config.mdx b/api_docs/kbn_axe_config.mdx index cd2250bbfe5ac..2aa9f72d7ac60 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-05-20 +date: 2024-05-23 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 18493c8dc8718..8060658bedec6 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-05-20 +date: 2024-05-23 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 d2b31ce98859c..bccadb2aa9cf5 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-05-20 +date: 2024-05-23 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 0eee9d95b4a8f..8f2836b0cc011 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-05-20 +date: 2024-05-23 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 29518f89e5848..0505c0ed31a6f 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-05-20 +date: 2024-05-23 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 6188e8d4e4310..921b502282746 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-05-20 +date: 2024-05-23 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 d1060783d23e5..3c75deaafda01 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-05-20 +date: 2024-05-23 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 534410c9302da..aefb620bfacc3 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-05-20 +date: 2024-05-23 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 b0e473d635928..20447907deec0 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-05-20 +date: 2024-05-23 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 9f8ec810a0beb..303445b25cd19 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-05-20 +date: 2024-05-23 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 ce73f8f8cca07..cd5aa7235a194 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-05-20 +date: 2024-05-23 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 69067a211490d..4a92ae38b364a 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-05-20 +date: 2024-05-23 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 6ab116495d9bb..e05ed6ee2f2c2 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-05-20 +date: 2024-05-23 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 e5a09418a4cf7..5cb16212bf368 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-05-20 +date: 2024-05-23 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 86fa8a1239df4..da99af61c0889 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-05-20 +date: 2024-05-23 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 cd38f5bf1a8d2..d7499cdee3567 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-05-20 +date: 2024-05-23 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 3f71b281bebfe..1dae616dc2d34 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-05-20 +date: 2024-05-23 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 b860f3d4dbb49..8d0dba1d7aae8 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-05-20 +date: 2024-05-23 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 99427ae691302..453edb2796747 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-05-20 +date: 2024-05-23 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 282e87f93cf19..0c6022ec43923 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-05-20 +date: 2024-05-23 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 f0730ac49dc9f..46c7c695b302c 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-05-20 +date: 2024-05-23 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 e9dd9c590fe78..c7029adf16696 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-05-20 +date: 2024-05-23 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 4ea257e9f4693..c4e471dd4e12d 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-05-20 +date: 2024-05-23 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 eba7e73df28e3..41ac3c65ad2e3 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-05-20 +date: 2024-05-23 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_utils.mdx b/api_docs/kbn_content_management_utils.mdx index f5ad856df42f2..496afe204c1cc 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-utils'] --- import kbnContentManagementUtilsObj from './kbn_content_management_utils.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser.mdx b/api_docs/kbn_core_analytics_browser.mdx index 60a7faf24d75e..09a502b98e53a 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-05-20 +date: 2024-05-23 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 52d781de782fc..76d06ad705cbb 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-05-20 +date: 2024-05-23 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 f1cf5126f992e..fd374c43a9f52 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser-mocks'] --- import kbnCoreAnalyticsBrowserMocksObj from './kbn_core_analytics_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server.mdx b/api_docs/kbn_core_analytics_server.mdx index 2f4a695a3ed53..a889ecddad55b 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-05-20 +date: 2024-05-23 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 eff968fe20d2d..24bd267b4e052 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-05-20 +date: 2024-05-23 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 185158860feee..be1e5f820e897 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-05-20 +date: 2024-05-23 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 3d0ea8e3ec7d6..61668021dad03 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-05-20 +date: 2024-05-23 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 ecc47ebaa0cfc..62ff4d97bdafb 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-05-20 +date: 2024-05-23 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 c776bc132b635..cbf8fdabdd96f 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-05-20 +date: 2024-05-23 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 9e4c892189ffa..11e0442e352dc 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-05-20 +date: 2024-05-23 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 c7cdaa131350d..d83583c346294 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-05-20 +date: 2024-05-23 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 8b8ceb5dcdc30..22adef9cea07b 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-05-20 +date: 2024-05-23 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 86c9e52e0e3f0..b7d4d7963e178 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-05-20 +date: 2024-05-23 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 81f88c68b532c..12cb4a10f828c 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-05-20 +date: 2024-05-23 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 119defe80e8d8..fa9fd8490ed60 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-05-20 +date: 2024-05-23 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 c2898e2946b88..bfa45c9efd6c1 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-05-20 +date: 2024-05-23 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 5f13b1c5433d8..d6b169ddacec0 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-05-20 +date: 2024-05-23 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 b52877a793a78..8dd86b89dda42 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-05-20 +date: 2024-05-23 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 893d300a007c7..79590cf5c651b 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-05-20 +date: 2024-05-23 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 a79edf2889cc0..59ae922c61002 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-05-20 +date: 2024-05-23 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 af6110cdeb0d0..1c9cc98fcf00c 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-05-20 +date: 2024-05-23 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 708e63bdc0164..eb8ba6a1f7234 100644 --- a/api_docs/kbn_core_chrome_browser.devdocs.json +++ b/api_docs/kbn_core_chrome_browser.devdocs.json @@ -3938,6 +3938,33 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/core-chrome-browser", + "id": "def-common.EuiSideNavItemTypeEnhanced", + "type": "Type", + "tags": [], + "label": "EuiSideNavItemTypeEnhanced", + "description": [ + "\nTemporary helper interface while we have to maintain both the legacy side navigation\nand the new \"solution view\" one. The legacy uses EuiSideNavItemType and its properties are not fully compatible\nwith the NodeDefinition. Solution teams declare their \"classic\" navigation using the EuiSideNavItemType.\nConverting those to the `NodeDefinition` require some additional props." + ], + "signature": [ + "Omit<", + "EuiSideNavItemType", + ", \"items\"> & { items?: ", + { + "pluginId": "@kbn/core-chrome-browser", + "scope": "common", + "docId": "kibKbnCoreChromeBrowserPluginApi", + "section": "def-common.EuiSideNavItemTypeEnhanced", + "text": "EuiSideNavItemTypeEnhanced" + }, + "[] | undefined; iconToString?: string | undefined; nameToString?: string | undefined; }" + ], + "path": "packages/core/chrome/core-chrome-browser/src/project_navigation.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/core-chrome-browser", "id": "def-common.EuiThemeSize", diff --git a/api_docs/kbn_core_chrome_browser.mdx b/api_docs/kbn_core_chrome_browser.mdx index 561f388dc4856..e6b40feeab237 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-chrome-browser'] --- import kbnCoreChromeBrowserObj from './kbn_core_chrome_browser.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 | |-------------------|-----------|------------------------|-----------------| -| 205 | 0 | 99 | 0 | +| 206 | 0 | 99 | 0 | ## Common diff --git a/api_docs/kbn_core_chrome_browser_mocks.mdx b/api_docs/kbn_core_chrome_browser_mocks.mdx index 6b1c3c2669c58..416001a0049d8 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-05-20 +date: 2024-05-23 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 809ec82628dc2..f97ce27be8fa8 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-05-20 +date: 2024-05-23 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 1888c71dc222e..05064c05e2988 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-05-20 +date: 2024-05-23 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 d872ef0b244f0..8fdeb892e955f 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-05-20 +date: 2024-05-23 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 8dc1b7e7b1d64..904c587d9163d 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-05-20 +date: 2024-05-23 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 c71457189c7b0..5daa60a3fe2f7 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-05-20 +date: 2024-05-23 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 cd134fe1ca899..f2d780792c135 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-05-20 +date: 2024-05-23 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 30e01ce4f57fe..5dfab814e980f 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-05-20 +date: 2024-05-23 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 3dd58bffce2a1..5b0c16d424446 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-05-20 +date: 2024-05-23 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 bb4457182fb78..5e93a4069ba03 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-05-20 +date: 2024-05-23 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 b92742537b0cf..4031958a4424d 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-05-20 +date: 2024-05-23 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 5a8c0b1d390ec..1fe31fda2f298 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-05-20 +date: 2024-05-23 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 11cbe6769aca8..0c1f61079fc84 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-05-20 +date: 2024-05-23 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 4ebdebbcefc41..4f4148d205c29 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-05-20 +date: 2024-05-23 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 d1d60c1286e56..7713c936c34d9 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-05-20 +date: 2024-05-23 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 65ddf2ae2bfa3..d029fce52aed9 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-05-20 +date: 2024-05-23 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 21b4324465695..26ff6b2fe4152 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-05-20 +date: 2024-05-23 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 936e409ff66d3..406c08c216813 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-05-20 +date: 2024-05-23 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 8b86585b41685..2736f7de73793 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-05-20 +date: 2024-05-23 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 58cb78c71fe10..72a8e24857de3 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-05-20 +date: 2024-05-23 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 8ac84befbf69c..838445c0493c2 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-05-20 +date: 2024-05-23 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 30511a404be73..3a412e08c73f3 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-05-20 +date: 2024-05-23 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 d0ff8f1de473f..47a8cef8a1ec8 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-05-20 +date: 2024-05-23 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 d7f6cc3720387..27ce31b8dc8cb 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-05-20 +date: 2024-05-23 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 fac72a013f43b..0599fa039d0ef 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-05-20 +date: 2024-05-23 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 4127b49887220..7aa60dd4e6286 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-05-20 +date: 2024-05-23 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 cdeced5ebdd5f..f8fb9c85efc19 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-05-20 +date: 2024-05-23 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 013294e2d7622..c57957e980f63 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-05-20 +date: 2024-05-23 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 8621e8d3c2e2e..10b8e957ed69c 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-05-20 +date: 2024-05-23 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 69587202b0f55..f08371cdd42f5 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-05-20 +date: 2024-05-23 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 2c43e99c5be70..04c2493698f1a 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-05-20 +date: 2024-05-23 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 650c2c5883b56..93b13ffe43e15 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-05-20 +date: 2024-05-23 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 58ee74f837063..83b0dc099cddc 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-05-20 +date: 2024-05-23 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 a1a31922adb06..48e89c0851602 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-05-20 +date: 2024-05-23 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 81ffc36c9db11..67f315b102642 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-05-20 +date: 2024-05-23 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 d79fa0cc8cb87..f3ac339105645 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-05-20 +date: 2024-05-23 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 2ffc1dac97282..f66ffcffaebcd 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-05-20 +date: 2024-05-23 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 51ab111ca359b..012f60bb98634 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-05-20 +date: 2024-05-23 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 426ce00b4bd15..fb7a7e3f209dc 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-05-20 +date: 2024-05-23 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 9d396f7034a82..3078e12fa7b2d 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-05-20 +date: 2024-05-23 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 f1d3850165adb..08bab1c41f590 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-05-20 +date: 2024-05-23 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 41b759d54336b..d05e5f3aa860d 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-05-20 +date: 2024-05-23 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 510eb73db7c09..14fd24e9ecbde 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-05-20 +date: 2024-05-23 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 c5f3f2ba85268..0504b1c435e94 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-05-20 +date: 2024-05-23 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 f6791e889e18f..22325c5a1a711 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-05-20 +date: 2024-05-23 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 32b1a6dcafc43..bc0d2bdd0c456 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-05-20 +date: 2024-05-23 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 f5febc6f53764..749facfa7f493 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-05-20 +date: 2024-05-23 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 33341437b0c70..a8bbf53184c4c 100644 --- a/api_docs/kbn_core_http_server.devdocs.json +++ b/api_docs/kbn_core_http_server.devdocs.json @@ -10938,6 +10938,35 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "@kbn/core-http-server", + "id": "def-common.KibanaRequest.httpVersion", + "type": "string", + "tags": [], + "label": "httpVersion", + "description": [ + "\nThe HTTP version sent by the client." + ], + "path": "packages/core/http/core-http-server/src/router/request.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-http-server", + "id": "def-common.KibanaRequest.protocol", + "type": "string", + "tags": [], + "label": "protocol", + "description": [ + "\nThe protocol used by the client, inferred from the httpVersion." + ], + "signature": [ + "\"http1\"" + ], + "path": "packages/core/http/core-http-server/src/router/request.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "@kbn/core-http-server", "id": "def-common.KibanaRequest.socket", @@ -16017,6 +16046,10 @@ "plugin": "synthetics", "path": "x-pack/plugins/observability_solution/synthetics/server/server.ts" }, + { + "plugin": "elasticAssistant", + "path": "x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/create_route.ts" + }, { "plugin": "controls", "path": "src/plugins/controls/server/options_list/options_list_suggestions_route.ts" @@ -17168,6 +17201,23 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/core-http-server", + "id": "def-common.HttpProtocol", + "type": "Type", + "tags": [], + "label": "HttpProtocol", + "description": [ + "\nDefines an http protocol.\n(Only supporting http1 for now)\n\n- http1: regroups all http/1.x protocols" + ], + "signature": [ + "\"http1\"" + ], + "path": "packages/core/http/core-http-server/src/http_contract.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/core-http-server", "id": "def-common.HttpResponsePayload", diff --git a/api_docs/kbn_core_http_server.mdx b/api_docs/kbn_core_http_server.mdx index cfd001143db62..d01d4c85efad1 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server'] --- import kbnCoreHttpServerObj from './kbn_core_http_server.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 483 | 2 | 193 | 0 | +| 486 | 2 | 193 | 0 | ## Common diff --git a/api_docs/kbn_core_http_server_internal.mdx b/api_docs/kbn_core_http_server_internal.mdx index f12330784e868..4327b61e875e2 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-05-20 +date: 2024-05-23 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 ae39c8aa3f7a7..54b121cf991b0 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-05-20 +date: 2024-05-23 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 23a25a57d3eb2..cd0765512ec35 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-05-20 +date: 2024-05-23 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 8ad00b1a48823..0933e52c12398 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-05-20 +date: 2024-05-23 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 32cd401da773a..53378bc849561 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-05-20 +date: 2024-05-23 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 0854f4c38ea98..2b0840d4711ce 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-05-20 +date: 2024-05-23 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 7f47ab316c544..572d617313351 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-05-20 +date: 2024-05-23 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 34a1c90381629..ae362582953e0 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-05-20 +date: 2024-05-23 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 9c91f7b5c652e..17a7a06da85d6 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-05-20 +date: 2024-05-23 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 84709ef3d39ae..a0d6ba499d7a6 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-05-20 +date: 2024-05-23 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 1b414a10e89b7..bc69591dffd47 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-05-20 +date: 2024-05-23 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 de22679913fb2..d091a8d8b9970 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-05-20 +date: 2024-05-23 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 d25d1d6e7ca21..85c58a9f80a11 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-05-20 +date: 2024-05-23 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 ee4919ebf5e8a..0282c968183a0 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-05-20 +date: 2024-05-23 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 1714bfd184514..011e1a102c8ae 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-05-20 +date: 2024-05-23 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 1880edca44f26..85505eba890b4 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-05-20 +date: 2024-05-23 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 c552d5b5c66d8..0326d3dcd951d 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-05-20 +date: 2024-05-23 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 e23a75f178d16..872ce803b6bb4 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-05-20 +date: 2024-05-23 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 fa24293b7e312..a10a1044ebf59 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-05-20 +date: 2024-05-23 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 f3b2b9e9767aa..cecbf56131bc1 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-05-20 +date: 2024-05-23 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 0d9a4d1466990..0c4582af520ba 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-05-20 +date: 2024-05-23 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 6d5a874cdcab8..074214142743b 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-05-20 +date: 2024-05-23 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 b3f6385ab4c76..be5c4309b865f 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-05-20 +date: 2024-05-23 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 74375c8683d14..18666b5fe5ecb 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-05-20 +date: 2024-05-23 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 f40af57c33616..6de70804b5700 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-05-20 +date: 2024-05-23 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 0d23253462dfb..03c867bb931fd 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-05-20 +date: 2024-05-23 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 3687e2abd36c7..0a5694b815a41 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-05-20 +date: 2024-05-23 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 394035fd76cfd..a0d4480276ffb 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-05-20 +date: 2024-05-23 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 79b00ba864792..5f8ab86815628 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-05-20 +date: 2024-05-23 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 64b82ef3698b9..e6daa2153794d 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-05-20 +date: 2024-05-23 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 d754835110cb8..4bb46a6008d4b 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-05-20 +date: 2024-05-23 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 477ae5b057835..18136d6d437b7 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-05-20 +date: 2024-05-23 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 3327fa9b318ae..f55e7b1600c97 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-05-20 +date: 2024-05-23 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 c657290d23f3b..7be81d3a7a456 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-05-20 +date: 2024-05-23 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 f87edc5118822..128a1da83d394 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-05-20 +date: 2024-05-23 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 6a85a491636be..3cc0c6b06257c 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-05-20 +date: 2024-05-23 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 a147aae398d78..6f187f457a4dd 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-05-20 +date: 2024-05-23 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 41d446c49fd61..0176b604e6ff7 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-05-20 +date: 2024-05-23 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 b088e990af2aa..5d991f7d10ce0 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-05-20 +date: 2024-05-23 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 e93e9f10e0655..0ffca2b829cc4 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-05-20 +date: 2024-05-23 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 6f5cdb2cc81af..9603370c70be6 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-05-20 +date: 2024-05-23 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 c7620c8dab10a..c27f97ab9db0a 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-05-20 +date: 2024-05-23 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 983f50bf92863..3dee649aab582 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-05-20 +date: 2024-05-23 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 8edd076bae49f..2fbc9c628c780 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-05-20 +date: 2024-05-23 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 a6c75edb284e3..5f1c26270029b 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-05-20 +date: 2024-05-23 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 646f86ddffb1d..acdeed9a333d2 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-05-20 +date: 2024-05-23 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 d054658727353..9e635cdd5b83c 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-05-20 +date: 2024-05-23 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 bf16f75d077d5..5180f239b4822 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-05-20 +date: 2024-05-23 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 69104f882c95b..1191a13561be2 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-05-20 +date: 2024-05-23 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.devdocs.json b/api_docs/kbn_core_saved_objects_base_server_internal.devdocs.json index a7c515398843f..d8680e1581ea2 100644 --- a/api_docs/kbn_core_saved_objects_base_server_internal.devdocs.json +++ b/api_docs/kbn_core_saved_objects_base_server_internal.devdocs.json @@ -2911,10 +2911,10 @@ }, { "parentPluginId": "@kbn/core-saved-objects-base-server-internal", - "id": "def-common.HASH_TO_VERSION_MAP.ingestpackagepoliciesa1a074bad36e68d54f98d2158d60f879", + "id": "def-common.HASH_TO_VERSION_MAP.ingestpackagepoliciesaef7977b81f7930f23cbfd8711ba272e", "type": "string", "tags": [], - "label": "'ingest-package-policies|a1a074bad36e68d54f98d2158d60f879'", + "label": "'ingest-package-policies|aef7977b81f7930f23cbfd8711ba272e'", "description": [], "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/constants.ts", "deprecated": false, 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 1215cbdf6be48..4dd816caf9564 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-05-20 +date: 2024-05-23 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 c684ae28d93d7..623f860a51466 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-05-20 +date: 2024-05-23 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 873f0c5a8ca7c..9df127b5f0021 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-05-20 +date: 2024-05-23 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 558e408949bc1..9c8131fe44a40 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-05-20 +date: 2024-05-23 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 385b9057258c1..d7d112daf6c9f 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-05-20 +date: 2024-05-23 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 0567167730911..e9c0c971f354a 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-05-20 +date: 2024-05-23 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 787138c6f15cf..204314ee7756e 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-05-20 +date: 2024-05-23 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 af20d6a5b716a..6f040f0cd2b0a 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-05-20 +date: 2024-05-23 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 547e8c067421e..9598eabb44e33 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-05-20 +date: 2024-05-23 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 afc85c60d3b77..790d97da1cc75 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-05-20 +date: 2024-05-23 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 7a316b93c571d..d1d045b4f4fce 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-05-20 +date: 2024-05-23 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 3d4f73061547b..d67937f85cd10 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-05-20 +date: 2024-05-23 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 9075e80015302..0f9a0f80b7853 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-05-20 +date: 2024-05-23 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 4cd03e888abab..ac7ddb314ea9b 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-05-20 +date: 2024-05-23 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 a130b207b281d..590a4102d299c 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-05-20 +date: 2024-05-23 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 886714cdf8b5c..11df2acee3716 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-05-20 +date: 2024-05-23 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 9a4e4ab30250c..aaea4d647f484 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-05-20 +date: 2024-05-23 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 784b57ee9703f..aa218a34d162f 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-05-20 +date: 2024-05-23 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 d0e080e22ff5d..0ac84865d8e04 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-05-20 +date: 2024-05-23 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 699fa40e70673..0a4ac147463f0 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-05-20 +date: 2024-05-23 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 81cb5989b1a83..4e12dd8b04809 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-05-20 +date: 2024-05-23 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 cbe81ddc53c79..05059a17425af 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-05-20 +date: 2024-05-23 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 a6ab0cdded4ae..5b50406bdd107 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-05-20 +date: 2024-05-23 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 0b6f7c0cb560d..4ed7dc982714e 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-05-20 +date: 2024-05-23 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 6727001ea7d80..767c9cdf92a3a 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-05-20 +date: 2024-05-23 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 557c4a6e00dd4..813dd15844599 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-05-20 +date: 2024-05-23 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 660b3da203adc..941dab6f53558 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-05-20 +date: 2024-05-23 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 3e666591c8547..22eeefe358f8f 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-05-20 +date: 2024-05-23 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 8c77a30d6bbca..6d22134d603b6 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-05-20 +date: 2024-05-23 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 4ba5a9bde15ba..1c016a750cf93 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-05-20 +date: 2024-05-23 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 60f194cd061db..7d918fb393052 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-05-20 +date: 2024-05-23 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 36bc1e3ebba5f..367cca99a3920 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-05-20 +date: 2024-05-23 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 0655750340378..c4e4153ed0d1e 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-05-20 +date: 2024-05-23 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 3a597038edc1c..052f3168deab3 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser-mocks'] --- import kbnCoreThemeBrowserMocksObj from './kbn_core_theme_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser.mdx b/api_docs/kbn_core_ui_settings_browser.mdx index 4a3ef71a5ee38..a4c6167437b4f 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-05-20 +date: 2024-05-23 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 03c8cea813f47..fa0d61cd632ab 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-05-20 +date: 2024-05-23 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 7681ee0ad948e..5e4f84b335aa8 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser-mocks'] --- import kbnCoreUiSettingsBrowserMocksObj from './kbn_core_ui_settings_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_common.mdx b/api_docs/kbn_core_ui_settings_common.mdx index c92582e578de8..5be2d8f295f24 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-common'] --- import kbnCoreUiSettingsCommonObj from './kbn_core_ui_settings_common.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_server.mdx b/api_docs/kbn_core_ui_settings_server.mdx index 878d3a8d57db0..2693265cf9dc8 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server'] --- import kbnCoreUiSettingsServerObj from './kbn_core_ui_settings_server.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_server_internal.mdx b/api_docs/kbn_core_ui_settings_server_internal.mdx index 4cf558fca1530..0f5193b78f6a8 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-05-20 +date: 2024-05-23 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 e5f208c7e76b1..9c3a59281a27e 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-05-20 +date: 2024-05-23 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 a70b2f2ef2e5d..87a61ee8fd58f 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-05-20 +date: 2024-05-23 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 6c242087b79ee..efa5562e7b347 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-05-20 +date: 2024-05-23 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 da199ae391538..2e45a79d06a21 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-05-20 +date: 2024-05-23 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 f6a183e6ed410..9e03f0262dddd 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-05-20 +date: 2024-05-23 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 081ba81ed87c2..37d282ccfcfc4 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-05-20 +date: 2024-05-23 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 d501ff9d9abfa..b42ad01437f85 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-05-20 +date: 2024-05-23 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 51a6773703431..cd49fbe49696a 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-05-20 +date: 2024-05-23 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 62077a80f00a4..505f04fb72e8d 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-05-20 +date: 2024-05-23 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 c2f3a4d5bba48..7d7b64cb6c6c0 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-05-20 +date: 2024-05-23 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 24df1b2fc824e..a371bfb6bb00d 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-05-20 +date: 2024-05-23 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 93aec5bc15e44..9e02cbec65598 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-05-20 +date: 2024-05-23 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 beeb99f06dba5..df9b263885a58 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-05-20 +date: 2024-05-23 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 e48726adf6cb9..e6115049f2273 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-05-20 +date: 2024-05-23 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 a63c76df61ca3..db4e3cb4602a5 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-05-20 +date: 2024-05-23 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 8f60f2d77a286..70e6cc09f5533 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-05-20 +date: 2024-05-23 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 cd8b527a77f95..ae086f207b86c 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-05-20 +date: 2024-05-23 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 18e59134e133e..1db6a04c4554d 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cypress-config'] --- import kbnCypressConfigObj from './kbn_cypress_config.devdocs.json'; diff --git a/api_docs/kbn_data_forge.devdocs.json b/api_docs/kbn_data_forge.devdocs.json index abc002a41da4b..232f42faa35b7 100644 --- a/api_docs/kbn_data_forge.devdocs.json +++ b/api_docs/kbn_data_forge.devdocs.json @@ -116,12 +116,31 @@ "label": "cli", "description": [], "signature": [ - "() => Promise" + "(cliOptions: ", + "CliOptions", + " | undefined) => Promise" ], "path": "x-pack/packages/kbn-data-forge/src/cli.ts", "deprecated": false, "trackAdoption": false, - "children": [], + "children": [ + { + "parentPluginId": "@kbn/data-forge", + "id": "def-common.cli.$1", + "type": "Object", + "tags": [], + "label": "cliOptions", + "description": [], + "signature": [ + "CliOptions", + " | undefined" + ], + "path": "x-pack/packages/kbn-data-forge/src/cli.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], "returnComment": [], "initialIsOpen": false }, @@ -469,6 +488,274 @@ "initialIsOpen": false } ], - "objects": [] + "objects": [ + { + "parentPluginId": "@kbn/data-forge", + "id": "def-common.DEFAULTS", + "type": "Object", + "tags": [], + "label": "DEFAULTS", + "description": [], + "path": "x-pack/packages/kbn-data-forge/src/constants.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/data-forge", + "id": "def-common.DEFAULTS.EVENTS_PER_CYCLE", + "type": "number", + "tags": [], + "label": "EVENTS_PER_CYCLE", + "description": [], + "path": "x-pack/packages/kbn-data-forge/src/constants.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/data-forge", + "id": "def-common.DEFAULTS.PAYLOAD_SIZE", + "type": "number", + "tags": [], + "label": "PAYLOAD_SIZE", + "description": [], + "path": "x-pack/packages/kbn-data-forge/src/constants.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/data-forge", + "id": "def-common.DEFAULTS.CONCURRENCY", + "type": "number", + "tags": [], + "label": "CONCURRENCY", + "description": [], + "path": "x-pack/packages/kbn-data-forge/src/constants.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/data-forge", + "id": "def-common.DEFAULTS.SERVERLESS", + "type": "boolean", + "tags": [], + "label": "SERVERLESS", + "description": [], + "path": "x-pack/packages/kbn-data-forge/src/constants.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/data-forge", + "id": "def-common.DEFAULTS.INDEX_INTERVAL", + "type": "number", + "tags": [], + "label": "INDEX_INTERVAL", + "description": [], + "path": "x-pack/packages/kbn-data-forge/src/constants.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/data-forge", + "id": "def-common.DEFAULTS.DATASET", + "type": "string", + "tags": [], + "label": "DATASET", + "description": [], + "path": "x-pack/packages/kbn-data-forge/src/constants.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/data-forge", + "id": "def-common.DEFAULTS.SCENARIO", + "type": "string", + "tags": [], + "label": "SCENARIO", + "description": [], + "path": "x-pack/packages/kbn-data-forge/src/constants.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/data-forge", + "id": "def-common.DEFAULTS.ELASTICSEARCH_HOST", + "type": "string", + "tags": [], + "label": "ELASTICSEARCH_HOST", + "description": [], + "path": "x-pack/packages/kbn-data-forge/src/constants.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/data-forge", + "id": "def-common.DEFAULTS.ELASTICSEARCH_USERNAME", + "type": "string", + "tags": [], + "label": "ELASTICSEARCH_USERNAME", + "description": [], + "path": "x-pack/packages/kbn-data-forge/src/constants.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/data-forge", + "id": "def-common.DEFAULTS.ELASTICSEARCH_PASSWORD", + "type": "string", + "tags": [], + "label": "ELASTICSEARCH_PASSWORD", + "description": [], + "path": "x-pack/packages/kbn-data-forge/src/constants.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/data-forge", + "id": "def-common.DEFAULTS.ELASTICSEARCH_API_KEY", + "type": "string", + "tags": [], + "label": "ELASTICSEARCH_API_KEY", + "description": [], + "path": "x-pack/packages/kbn-data-forge/src/constants.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/data-forge", + "id": "def-common.DEFAULTS.SKIP_KIBANA_USER", + "type": "boolean", + "tags": [], + "label": "SKIP_KIBANA_USER", + "description": [], + "path": "x-pack/packages/kbn-data-forge/src/constants.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/data-forge", + "id": "def-common.DEFAULTS.INSTALL_KIBANA_ASSETS", + "type": "boolean", + "tags": [], + "label": "INSTALL_KIBANA_ASSETS", + "description": [], + "path": "x-pack/packages/kbn-data-forge/src/constants.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/data-forge", + "id": "def-common.DEFAULTS.DELAY_IN_MINUTES", + "type": "number", + "tags": [], + "label": "DELAY_IN_MINUTES", + "description": [], + "path": "x-pack/packages/kbn-data-forge/src/constants.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/data-forge", + "id": "def-common.DEFAULTS.DELAY_EVERY_MINUTES", + "type": "number", + "tags": [], + "label": "DELAY_EVERY_MINUTES", + "description": [], + "path": "x-pack/packages/kbn-data-forge/src/constants.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/data-forge", + "id": "def-common.DEFAULTS.LOOKBACK", + "type": "string", + "tags": [], + "label": "LOOKBACK", + "description": [], + "path": "x-pack/packages/kbn-data-forge/src/constants.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/data-forge", + "id": "def-common.DEFAULTS.KIBANA_URL", + "type": "string", + "tags": [], + "label": "KIBANA_URL", + "description": [], + "path": "x-pack/packages/kbn-data-forge/src/constants.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/data-forge", + "id": "def-common.DEFAULTS.KIBANA_USERNAME", + "type": "string", + "tags": [], + "label": "KIBANA_USERNAME", + "description": [], + "path": "x-pack/packages/kbn-data-forge/src/constants.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/data-forge", + "id": "def-common.DEFAULTS.KIBANA_PASSWORD", + "type": "string", + "tags": [], + "label": "KIBANA_PASSWORD", + "description": [], + "path": "x-pack/packages/kbn-data-forge/src/constants.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/data-forge", + "id": "def-common.DEFAULTS.EVENT_TEMPLATE", + "type": "string", + "tags": [], + "label": "EVENT_TEMPLATE", + "description": [], + "path": "x-pack/packages/kbn-data-forge/src/constants.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/data-forge", + "id": "def-common.DEFAULTS.REDUCE_WEEKEND_TRAFFIC_BY", + "type": "number", + "tags": [], + "label": "REDUCE_WEEKEND_TRAFFIC_BY", + "description": [], + "path": "x-pack/packages/kbn-data-forge/src/constants.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/data-forge", + "id": "def-common.DEFAULTS.EPHEMERAL_PROJECT_IDS", + "type": "number", + "tags": [], + "label": "EPHEMERAL_PROJECT_IDS", + "description": [], + "path": "x-pack/packages/kbn-data-forge/src/constants.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/data-forge", + "id": "def-common.DEFAULTS.ALIGN_EVENTS_TO_INTERVAL", + "type": "boolean", + "tags": [], + "label": "ALIGN_EVENTS_TO_INTERVAL", + "description": [], + "path": "x-pack/packages/kbn-data-forge/src/constants.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ] } } \ No newline at end of file diff --git a/api_docs/kbn_data_forge.mdx b/api_docs/kbn_data_forge.mdx index 77b427641fd06..5f6dc75f19bfb 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-forge'] --- import kbnDataForgeObj from './kbn_data_forge.devdocs.json'; @@ -21,10 +21,13 @@ Contact [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/ | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 26 | 0 | 26 | 0 | +| 51 | 0 | 51 | 1 | ## Common +### Objects + + ### Functions diff --git a/api_docs/kbn_data_service.mdx b/api_docs/kbn_data_service.mdx index f7c8cd4f79e50..637b20b0dd222 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-05-20 +date: 2024-05-23 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 b3122f7ae51bd..7de149547a1b2 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-05-20 +date: 2024-05-23 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 aa2394b3a95fd..a1d07415b13d6 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-05-20 +date: 2024-05-23 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 1d246c0a39d21..e959cfdbf4f38 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-05-20 +date: 2024-05-23 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 c07271541acd8..ed1ab422b755c 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-05-20 +date: 2024-05-23 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 6adb69716e382..e9d0c30633a5c 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-05-20 +date: 2024-05-23 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 4fc9389ec9b65..5bda451c6ff7b 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-05-20 +date: 2024-05-23 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 7b777f89de6b1..943e6bce11686 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-05-20 +date: 2024-05-23 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 ed60480d3d0fe..ded4d6ac940e7 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-05-20 +date: 2024-05-23 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 8d3ff8af26804..6737d9b81dae2 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-05-20 +date: 2024-05-23 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 aa1a17f089365..1b835f08d82a5 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-05-20 +date: 2024-05-23 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 187a9890bda0d..ccb5c743a002e 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-05-20 +date: 2024-05-23 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 a4b5c02061939..a61a526506641 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-05-20 +date: 2024-05-23 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 03124f5a248c1..6fd0ef80074bd 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-05-20 +date: 2024-05-23 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 36894a36fd468..2840dcca13633 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-05-20 +date: 2024-05-23 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 7dd0d287bacf4..815a5c51c5258 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-05-20 +date: 2024-05-23 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 ce652d54e07ab..69737cd82562c 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-05-20 +date: 2024-05-23 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 c46e74bd04532..720d30fd8d730 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-05-20 +date: 2024-05-23 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 6918c4038640c..dae31a32ac748 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-05-20 +date: 2024-05-23 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 9868b51309251..553de33087153 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-05-20 +date: 2024-05-23 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 772a9c2e99188..8e221a5fc4993 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-utils'] --- import kbnDevUtilsObj from './kbn_dev_utils.devdocs.json'; diff --git a/api_docs/kbn_discover_utils.mdx b/api_docs/kbn_discover_utils.mdx index 2bb02673cbaec..b12cab3c10a84 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/discover-utils'] --- import kbnDiscoverUtilsObj from './kbn_discover_utils.devdocs.json'; diff --git a/api_docs/kbn_doc_links.devdocs.json b/api_docs/kbn_doc_links.devdocs.json index db61b6fa68e9e..56152abc3712d 100644 --- a/api_docs/kbn_doc_links.devdocs.json +++ b/api_docs/kbn_doc_links.devdocs.json @@ -840,7 +840,7 @@ "label": "fleet", "description": [], "signature": [ - "{ readonly beatsAgentComparison: string; readonly guide: string; readonly fleetServer: string; readonly fleetServerAddFleetServer: string; readonly esSettings: string; readonly settings: string; readonly logstashSettings: string; readonly kafkaSettings: string; readonly settingsFleetServerHostSettings: string; readonly settingsFleetServerProxySettings: string; readonly troubleshooting: string; readonly elasticAgent: string; readonly datastreams: string; readonly datastreamsILM: string; readonly datastreamsNamingScheme: string; readonly datastreamsManualRollover: string; readonly datastreamsTSDS: string; readonly datastreamsTSDSMetrics: string; readonly installElasticAgent: string; readonly installElasticAgentStandalone: string; readonly packageSignatures: string; readonly upgradeElasticAgent: string; readonly learnMoreBlog: string; readonly apiKeysLearnMore: string; readonly onPremRegistry: string; readonly secureLogstash: string; readonly agentPolicy: string; readonly api: string; readonly uninstallAgent: string; readonly installAndUninstallIntegrationAssets: string; readonly elasticAgentInputConfiguration: string; readonly policySecrets: string; readonly remoteESOoutput: string; readonly performancePresets: string; readonly scalingKubernetesResourcesAndLimits: string; }" + "{ readonly beatsAgentComparison: string; readonly guide: string; readonly fleetServer: string; readonly fleetServerAddFleetServer: string; readonly esSettings: string; readonly settings: string; readonly logstashSettings: string; readonly kafkaSettings: string; readonly settingsFleetServerHostSettings: string; readonly settingsFleetServerProxySettings: string; readonly troubleshooting: string; readonly elasticAgent: string; readonly datastreams: string; readonly datastreamsILM: string; readonly datastreamsNamingScheme: string; readonly datastreamsManualRollover: string; readonly datastreamsTSDS: string; readonly datastreamsTSDSMetrics: string; readonly installElasticAgent: string; readonly installElasticAgentStandalone: string; readonly packageSignatures: string; readonly upgradeElasticAgent: string; readonly learnMoreBlog: string; readonly apiKeysLearnMore: string; readonly onPremRegistry: string; readonly secureLogstash: string; readonly agentPolicy: string; readonly api: string; readonly uninstallAgent: string; readonly installAndUninstallIntegrationAssets: string; readonly elasticAgentInputConfiguration: string; readonly policySecrets: string; readonly remoteESOoutput: string; readonly performancePresets: string; readonly scalingKubernetesResourcesAndLimits: string; readonly roleAndPrivileges: string; }" ], "path": "packages/kbn-doc-links/src/types.ts", "deprecated": false, diff --git a/api_docs/kbn_doc_links.mdx b/api_docs/kbn_doc_links.mdx index cab07f28209d1..a1e47fbfbaeca 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-05-20 +date: 2024-05-23 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 0358613769c72..23d54a9f482be 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-05-20 +date: 2024-05-23 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 64ffd0d644200..edae7960db8c0 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dom-drag-drop'] --- import kbnDomDragDropObj from './kbn_dom_drag_drop.devdocs.json'; diff --git a/api_docs/kbn_ebt_tools.mdx b/api_docs/kbn_ebt_tools.mdx index b9973c05fa579..e6299fda07c2f 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-05-20 +date: 2024-05-23 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 a3030a1edd466..9cd7b9d8de3b2 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-05-20 +date: 2024-05-23 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 962f4257ed9c1..f01142416a0b2 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-agent-utils'] --- import kbnElasticAgentUtilsObj from './kbn_elastic_agent_utils.devdocs.json'; diff --git a/api_docs/kbn_elastic_assistant.devdocs.json b/api_docs/kbn_elastic_assistant.devdocs.json index 15d2789e99175..edb7425fa9508 100644 --- a/api_docs/kbn_elastic_assistant.devdocs.json +++ b/api_docs/kbn_elastic_assistant.devdocs.json @@ -2192,117 +2192,6 @@ ], "initialIsOpen": false }, - { - "parentPluginId": "@kbn/elastic-assistant", - "id": "def-public.DeleteKnowledgeBaseResponse", - "type": "Interface", - "tags": [], - "label": "DeleteKnowledgeBaseResponse", - "description": [], - "path": "x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/elastic-assistant", - "id": "def-public.DeleteKnowledgeBaseResponse.success", - "type": "boolean", - "tags": [], - "label": "success", - "description": [], - "path": "x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.tsx", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/elastic-assistant", - "id": "def-public.GetKnowledgeBaseStatusResponse", - "type": "Interface", - "tags": [], - "label": "GetKnowledgeBaseStatusResponse", - "description": [], - "path": "x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/elastic-assistant", - "id": "def-public.GetKnowledgeBaseStatusResponse.elser_exists", - "type": "boolean", - "tags": [], - "label": "elser_exists", - "description": [], - "path": "x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.tsx", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/elastic-assistant", - "id": "def-public.GetKnowledgeBaseStatusResponse.esql_exists", - "type": "CompoundType", - "tags": [], - "label": "esql_exists", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.tsx", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/elastic-assistant", - "id": "def-public.GetKnowledgeBaseStatusResponse.index_exists", - "type": "boolean", - "tags": [], - "label": "index_exists", - "description": [], - "path": "x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.tsx", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/elastic-assistant", - "id": "def-public.GetKnowledgeBaseStatusResponse.pipeline_exists", - "type": "boolean", - "tags": [], - "label": "pipeline_exists", - "description": [], - "path": "x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.tsx", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/elastic-assistant", - "id": "def-public.PostKnowledgeBaseResponse", - "type": "Interface", - "tags": [], - "label": "PostKnowledgeBaseResponse", - "description": [], - "path": "x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/elastic-assistant", - "id": "def-public.PostKnowledgeBaseResponse.success", - "type": "boolean", - "tags": [], - "label": "success", - "description": [], - "path": "x-pack/packages/kbn-elastic-assistant/impl/assistant/api/index.tsx", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, { "parentPluginId": "@kbn/elastic-assistant", "id": "def-public.Prompt", diff --git a/api_docs/kbn_elastic_assistant.mdx b/api_docs/kbn_elastic_assistant.mdx index 0bc60bbc90ce4..69f8c8053c59a 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-assistant'] --- import kbnElasticAssistantObj from './kbn_elastic_assistant.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/security-generative-ai](https://github.com/orgs/elastic/teams/ | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 174 | 0 | 147 | 9 | +| 165 | 0 | 138 | 9 | ## Client diff --git a/api_docs/kbn_elastic_assistant_common.devdocs.json b/api_docs/kbn_elastic_assistant_common.devdocs.json index d1ac54ba561ff..99c152889d5a3 100644 --- a/api_docs/kbn_elastic_assistant_common.devdocs.json +++ b/api_docs/kbn_elastic_assistant_common.devdocs.json @@ -400,6 +400,74 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.parseBedrockBuffer", + "type": "Function", + "tags": [], + "label": "parseBedrockBuffer", + "description": [ + "\nParses a Bedrock buffer from an array of chunks.\n" + ], + "signature": [ + "(chunks: Uint8Array[], logger: ", + { + "pluginId": "@kbn/logging", + "scope": "common", + "docId": "kibKbnLoggingPluginApi", + "section": "def-common.Logger", + "text": "Logger" + }, + ") => string" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/utils/bedrock.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.parseBedrockBuffer.$1", + "type": "Array", + "tags": [], + "label": "chunks", + "description": [ + "- Array of Uint8Array chunks to be parsed." + ], + "signature": [ + "Uint8Array[]" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/utils/bedrock.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.parseBedrockBuffer.$2", + "type": "Object", + "tags": [], + "label": "logger", + "description": [], + "signature": [ + { + "pluginId": "@kbn/logging", + "scope": "common", + "docId": "kibKbnLoggingPluginApi", + "section": "def-common.Logger", + "text": "Logger" + } + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/utils/bedrock.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [ + "- Parsed string from the Bedrock buffer." + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/elastic-assistant-common", "id": "def-common.replaceAnonymizedValuesWithOriginalValues", @@ -776,7 +844,7 @@ "\nInterface for features available to the elastic assistant" ], "signature": [ - "{ readonly assistantModelEvaluation: boolean; }" + "{ readonly assistantKnowledgeBaseByDefault: boolean; readonly assistantModelEvaluation: boolean; }" ], "path": "x-pack/packages/kbn-elastic-assistant-common/impl/capabilities/index.ts", "deprecated": false, @@ -1134,6 +1202,51 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.CreateKnowledgeBaseEntryRequestBody", + "type": "Type", + "tags": [], + "label": "CreateKnowledgeBaseEntryRequestBody", + "description": [], + "signature": [ + "{ text: string; metadata: { source: string; required: boolean; kbResource: string; }; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_knowledge_base_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.CreateKnowledgeBaseEntryRequestBodyInput", + "type": "Type", + "tags": [], + "label": "CreateKnowledgeBaseEntryRequestBodyInput", + "description": [], + "signature": [ + "{ text: string; metadata: { source: string; required: boolean; kbResource: string; }; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_knowledge_base_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.CreateKnowledgeBaseEntryResponse", + "type": "Type", + "tags": [], + "label": "CreateKnowledgeBaseEntryResponse", + "description": [], + "signature": [ + "{ id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_knowledge_base_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/elastic-assistant-common", "id": "def-common.CreateKnowledgeBaseRequestParams", @@ -1254,6 +1367,51 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.DeleteKnowledgeBaseEntryRequestParams", + "type": "Type", + "tags": [], + "label": "DeleteKnowledgeBaseEntryRequestParams", + "description": [], + "signature": [ + "{ id: string; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_knowledge_base_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.DeleteKnowledgeBaseEntryRequestParamsInput", + "type": "Type", + "tags": [], + "label": "DeleteKnowledgeBaseEntryRequestParamsInput", + "description": [], + "signature": [ + "{ id: string; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_knowledge_base_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.DeleteKnowledgeBaseEntryResponse", + "type": "Type", + "tags": [], + "label": "DeleteKnowledgeBaseEntryResponse", + "description": [], + "signature": [ + "{ id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_knowledge_base_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/elastic-assistant-common", "id": "def-common.DeleteKnowledgeBaseRequestParams", @@ -1410,6 +1568,57 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.ELASTIC_AI_ASSISTANT_INTERNAL_URL", + "type": "string", + "tags": [], + "label": "ELASTIC_AI_ASSISTANT_INTERNAL_URL", + "description": [], + "signature": [ + "\"/internal/elastic_assistant\"" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_ENTRIES_URL", + "type": "string", + "tags": [], + "label": "ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_ENTRIES_URL", + "description": [], + "path": "x-pack/packages/kbn-elastic-assistant-common/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_ENTRIES_URL_BULK_ACTION", + "type": "string", + "tags": [], + "label": "ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_ENTRIES_URL_BULK_ACTION", + "description": [], + "path": "x-pack/packages/kbn-elastic-assistant-common/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_URL", + "type": "string", + "tags": [], + "label": "ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_URL", + "description": [], + "path": "x-pack/packages/kbn-elastic-assistant-common/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/elastic-assistant-common", "id": "def-common.ELASTIC_AI_ASSISTANT_PROMPTS_URL", @@ -1679,7 +1888,7 @@ "label": "GetCapabilitiesResponse", "description": [], "signature": [ - "{ assistantModelEvaluation: boolean; }" + "{ assistantKnowledgeBaseByDefault: boolean; assistantModelEvaluation: boolean; }" ], "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/capabilities/get_capabilities_route.gen.ts", "deprecated": false, @@ -1718,216 +1927,458 @@ }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.KnowledgeBaseResponse", + "id": "def-common.KnowledgeBaseEntryBulkActionBase", "type": "Type", "tags": [], - "label": "KnowledgeBaseResponse", - "description": [ - "\nAI assistant KnowledgeBase." - ], + "label": "KnowledgeBaseEntryBulkActionBase", + "description": [], "signature": [ - "{ success?: boolean | undefined; }" + "{ query?: string | undefined; ids?: string[] | undefined; }" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/bulk_crud_knowledge_base_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.Message", + "id": "def-common.KnowledgeBaseEntryBulkActionSkipReason", "type": "Type", "tags": [], - "label": "Message", - "description": [ - "\nAI assistant conversation message." - ], + "label": "KnowledgeBaseEntryBulkActionSkipReason", + "description": [], "signature": [ - "{ timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }" + "\"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\"" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/bulk_crud_knowledge_base_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.MessageRole", + "id": "def-common.KnowledgeBaseEntryBulkActionSkipResult", "type": "Type", "tags": [], - "label": "MessageRole", - "description": [ - "\nMessage role." - ], + "label": "KnowledgeBaseEntryBulkActionSkipResult", + "description": [], "signature": [ - "\"user\" | \"system\" | \"assistant\"" + "{ id: string; skip_reason: \"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\"; name?: string | undefined; }" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/bulk_crud_knowledge_base_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.MessageRoleEnum", + "id": "def-common.KnowledgeBaseEntryBulkCrudActionResponse", "type": "Type", "tags": [], - "label": "MessageRoleEnum", + "label": "KnowledgeBaseEntryBulkCrudActionResponse", "description": [], "signature": [ - "{ user: \"user\"; system: \"system\"; assistant: \"assistant\"; }" + "{ attributes: { results: { created: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; updated: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; skipped: { id: string; skip_reason: \"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }; summary: { total: number; succeeded: number; failed: number; skipped: number; }; errors?: { message: string; statusCode: number; knowledgeBaseEntries: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }[] | undefined; }; success?: boolean | undefined; statusCode?: number | undefined; message?: string | undefined; knowledgeBaseEntriesCount?: number | undefined; }" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/bulk_crud_knowledge_base_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.NonEmptyString", + "id": "def-common.KnowledgeBaseEntryBulkCrudActionResults", "type": "Type", "tags": [], - "label": "NonEmptyString", - "description": [ - "\nA string that is not empty and does not contain only whitespace" - ], + "label": "KnowledgeBaseEntryBulkCrudActionResults", + "description": [], "signature": [ - "string" + "{ created: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; updated: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; skipped: { id: string; skip_reason: \"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/bulk_crud_knowledge_base_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.NormalizedConversationError", + "id": "def-common.KnowledgeBaseEntryBulkCrudActionSummary", "type": "Type", "tags": [], - "label": "NormalizedConversationError", + "label": "KnowledgeBaseEntryBulkCrudActionSummary", "description": [], "signature": [ - "{ message: string; status_code: number; conversations: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }" + "{ total: number; succeeded: number; failed: number; skipped: number; }" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/bulk_crud_conversations_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/bulk_crud_knowledge_base_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.OutputIndex", + "id": "def-common.KnowledgeBaseEntryCreateProps", "type": "Type", "tags": [], - "label": "OutputIndex", + "label": "KnowledgeBaseEntryCreateProps", "description": [], "signature": [ - "string" + "{ text: string; metadata: { source: string; required: boolean; kbResource: string; }; }" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/evaluation/post_evaluate_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/common_attributes.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.PerformBulkActionRequestBody", + "id": "def-common.KnowledgeBaseEntryDetailsInError", "type": "Type", "tags": [], - "label": "PerformBulkActionRequestBody", + "label": "KnowledgeBaseEntryDetailsInError", "description": [], "signature": [ - "{ delete?: { query?: string | undefined; ids?: string[] | undefined; } | undefined; create?: { title: string; id?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; }[] | undefined; update?: { id: string; title?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; }[] | undefined; }" + "{ id: string; name?: string | undefined; }" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/bulk_crud_conversations_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/bulk_crud_knowledge_base_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.PerformBulkActionRequestBodyInput", + "id": "def-common.KnowledgeBaseEntryErrorSchema", "type": "Type", "tags": [], - "label": "PerformBulkActionRequestBodyInput", + "label": "KnowledgeBaseEntryErrorSchema", "description": [], "signature": [ - "{ delete?: { query?: string | undefined; ids?: string[] | undefined; } | undefined; create?: { title: string; id?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; }[] | undefined; update?: { id: string; title?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; }[] | undefined; }" + "{ error: string; message: string; statusCode: number; }" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/bulk_crud_conversations_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/common_attributes.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.PerformBulkActionResponse", + "id": "def-common.KnowledgeBaseEntryResponse", "type": "Type", "tags": [], - "label": "PerformBulkActionResponse", + "label": "KnowledgeBaseEntryResponse", "description": [], "signature": [ - "{ attributes: { results: { created: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; updated: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; skipped: { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }; summary: { total: number; succeeded: number; failed: number; skipped: number; }; errors?: { message: string; status_code: number; conversations: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }[] | undefined; }; success?: boolean | undefined; status_code?: number | undefined; message?: string | undefined; conversations_count?: number | undefined; }" + "{ id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/bulk_crud_conversations_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/common_attributes.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.PostEvaluateBody", + "id": "def-common.KnowledgeBaseEntryUpdateProps", "type": "Type", "tags": [], - "label": "PostEvaluateBody", + "label": "KnowledgeBaseEntryUpdateProps", "description": [], "signature": [ - "{ dataset?: { input: string; reference: string; id?: string | undefined; prediction?: string | undefined; tags?: string[] | undefined; }[] | undefined; evalPrompt?: string | undefined; }" + "{ id: string; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; }" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/evaluation/post_evaluate_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/common_attributes.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.PostEvaluateRequestBody", + "id": "def-common.KnowledgeBaseResponse", "type": "Type", "tags": [], - "label": "PostEvaluateRequestBody", - "description": [], + "label": "KnowledgeBaseResponse", + "description": [ + "\nAI assistant KnowledgeBase." + ], "signature": [ - "{ dataset?: { input: string; reference: string; id?: string | undefined; prediction?: string | undefined; tags?: string[] | undefined; }[] | undefined; evalPrompt?: string | undefined; }" + "{ success?: boolean | undefined; }" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/evaluation/post_evaluate_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.PostEvaluateRequestBodyInput", + "id": "def-common.Message", "type": "Type", "tags": [], - "label": "PostEvaluateRequestBodyInput", - "description": [], + "label": "Message", + "description": [ + "\nAI assistant conversation message." + ], "signature": [ - "{ dataset?: { input: string; reference: string; id?: string | undefined; prediction?: string | undefined; tags?: string[] | undefined; }[] | undefined; evalPrompt?: string | undefined; }" + "{ timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/evaluation/post_evaluate_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.PostEvaluateRequestQuery", + "id": "def-common.MessageRole", "type": "Type", "tags": [], - "label": "PostEvaluateRequestQuery", - "description": [], + "label": "MessageRole", + "description": [ + "\nMessage role." + ], "signature": [ - "{ agents: string; models: string; outputIndex: string; datasetName?: string | undefined; evaluationType?: string | undefined; evalModel?: string | undefined; projectName?: string | undefined; runName?: string | undefined; }" + "\"user\" | \"system\" | \"assistant\"" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.MessageRoleEnum", + "type": "Type", + "tags": [], + "label": "MessageRoleEnum", + "description": [], + "signature": [ + "{ user: \"user\"; system: \"system\"; assistant: \"assistant\"; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.Metadata", + "type": "Type", + "tags": [], + "label": "Metadata", + "description": [ + "\nMetadata about an Knowledge Base Entry" + ], + "signature": [ + "{ source: string; required: boolean; kbResource: string; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/common_attributes.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.NonEmptyString", + "type": "Type", + "tags": [], + "label": "NonEmptyString", + "description": [ + "\nA string that is not empty and does not contain only whitespace" + ], + "signature": [ + "string" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.NormalizedConversationError", + "type": "Type", + "tags": [], + "label": "NormalizedConversationError", + "description": [], + "signature": [ + "{ message: string; status_code: number; conversations: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/bulk_crud_conversations_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.NormalizedKnowledgeBaseEntryError", + "type": "Type", + "tags": [], + "label": "NormalizedKnowledgeBaseEntryError", + "description": [], + "signature": [ + "{ message: string; statusCode: number; knowledgeBaseEntries: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/bulk_crud_knowledge_base_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.OutputIndex", + "type": "Type", + "tags": [], + "label": "OutputIndex", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/evaluation/post_evaluate_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.PerformBulkActionRequestBody", + "type": "Type", + "tags": [], + "label": "PerformBulkActionRequestBody", + "description": [], + "signature": [ + "{ delete?: { query?: string | undefined; ids?: string[] | undefined; } | undefined; create?: { title: string; id?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; }[] | undefined; update?: { id: string; title?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; }[] | undefined; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/bulk_crud_conversations_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.PerformBulkActionRequestBodyInput", + "type": "Type", + "tags": [], + "label": "PerformBulkActionRequestBodyInput", + "description": [], + "signature": [ + "{ delete?: { query?: string | undefined; ids?: string[] | undefined; } | undefined; create?: { title: string; id?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; }[] | undefined; update?: { id: string; title?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; }[] | undefined; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/bulk_crud_conversations_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.PerformBulkActionResponse", + "type": "Type", + "tags": [], + "label": "PerformBulkActionResponse", + "description": [], + "signature": [ + "{ attributes: { results: { created: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; updated: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; skipped: { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }; summary: { total: number; succeeded: number; failed: number; skipped: number; }; errors?: { message: string; status_code: number; conversations: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }[] | undefined; }; success?: boolean | undefined; status_code?: number | undefined; message?: string | undefined; conversations_count?: number | undefined; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/bulk_crud_conversations_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.PerformKnowledgeBaseEntryBulkActionRequestBody", + "type": "Type", + "tags": [], + "label": "PerformKnowledgeBaseEntryBulkActionRequestBody", + "description": [], + "signature": [ + "{ delete?: { query?: string | undefined; ids?: string[] | undefined; } | undefined; create?: { text: string; metadata: { source: string; required: boolean; kbResource: string; }; }[] | undefined; update?: { id: string; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; }[] | undefined; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/bulk_crud_knowledge_base_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.PerformKnowledgeBaseEntryBulkActionRequestBodyInput", + "type": "Type", + "tags": [], + "label": "PerformKnowledgeBaseEntryBulkActionRequestBodyInput", + "description": [], + "signature": [ + "{ delete?: { query?: string | undefined; ids?: string[] | undefined; } | undefined; create?: { text: string; metadata: { source: string; required: boolean; kbResource: string; }; }[] | undefined; update?: { id: string; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; }[] | undefined; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/bulk_crud_knowledge_base_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.PerformKnowledgeBaseEntryBulkActionResponse", + "type": "Type", + "tags": [], + "label": "PerformKnowledgeBaseEntryBulkActionResponse", + "description": [], + "signature": [ + "{ attributes: { results: { created: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; updated: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; skipped: { id: string; skip_reason: \"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }; summary: { total: number; succeeded: number; failed: number; skipped: number; }; errors?: { message: string; statusCode: number; knowledgeBaseEntries: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }[] | undefined; }; success?: boolean | undefined; statusCode?: number | undefined; message?: string | undefined; knowledgeBaseEntriesCount?: number | undefined; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/bulk_crud_knowledge_base_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.PostEvaluateBody", + "type": "Type", + "tags": [], + "label": "PostEvaluateBody", + "description": [], + "signature": [ + "{ dataset?: { input: string; reference: string; id?: string | undefined; prediction?: string | undefined; tags?: string[] | undefined; }[] | undefined; evalPrompt?: string | undefined; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/evaluation/post_evaluate_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.PostEvaluateRequestBody", + "type": "Type", + "tags": [], + "label": "PostEvaluateRequestBody", + "description": [], + "signature": [ + "{ dataset?: { input: string; reference: string; id?: string | undefined; prediction?: string | undefined; tags?: string[] | undefined; }[] | undefined; evalPrompt?: string | undefined; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/evaluation/post_evaluate_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.PostEvaluateRequestBodyInput", + "type": "Type", + "tags": [], + "label": "PostEvaluateRequestBodyInput", + "description": [], + "signature": [ + "{ dataset?: { input: string; reference: string; id?: string | undefined; prediction?: string | undefined; tags?: string[] | undefined; }[] | undefined; evalPrompt?: string | undefined; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/evaluation/post_evaluate_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.PostEvaluateRequestQuery", + "type": "Type", + "tags": [], + "label": "PostEvaluateRequestQuery", + "description": [], + "signature": [ + "{ agents: string; models: string; outputIndex: string; datasetName?: string | undefined; evaluationType?: string | undefined; evalModel?: string | undefined; projectName?: string | undefined; runName?: string | undefined; }" ], "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/evaluation/post_evaluate_route.gen.ts", "deprecated": false, @@ -2071,6 +2522,51 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.ReadKnowledgeBaseEntryRequestParams", + "type": "Type", + "tags": [], + "label": "ReadKnowledgeBaseEntryRequestParams", + "description": [], + "signature": [ + "{ id: string; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_knowledge_base_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.ReadKnowledgeBaseEntryRequestParamsInput", + "type": "Type", + "tags": [], + "label": "ReadKnowledgeBaseEntryRequestParamsInput", + "description": [], + "signature": [ + "{ id: string; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_knowledge_base_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.ReadKnowledgeBaseEntryResponse", + "type": "Type", + "tags": [], + "label": "ReadKnowledgeBaseEntryResponse", + "description": [], + "signature": [ + "{ id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_knowledge_base_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/elastic-assistant-common", "id": "def-common.ReadKnowledgeBaseRequestParams", @@ -2109,7 +2605,7 @@ "label": "ReadKnowledgeBaseResponse", "description": [], "signature": [ - "{ elser_exists?: boolean | undefined; index_exists?: boolean | undefined; pipeline_exists?: boolean | undefined; }" + "{ elser_exists?: boolean | undefined; esql_exists?: boolean | undefined; index_exists?: boolean | undefined; is_setup_in_progress?: boolean | undefined; pipeline_exists?: boolean | undefined; }" ], "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.gen.ts", "deprecated": false, @@ -2156,101 +2652,176 @@ "label": "SortOrderEnum", "description": [], "signature": [ - "{ asc: \"asc\"; desc: \"desc\"; }" + "{ asc: \"asc\"; desc: \"desc\"; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.TraceData", + "type": "Type", + "tags": [], + "label": "TraceData", + "description": [ + "\ntrace Data" + ], + "signature": [ + "{ transactionId?: string | undefined; traceId?: string | undefined; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.UpdateConversationRequestBody", + "type": "Type", + "tags": [], + "label": "UpdateConversationRequestBody", + "description": [], + "signature": [ + "{ id: string; title?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/crud_conversation_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.UpdateConversationRequestBodyInput", + "type": "Type", + "tags": [], + "label": "UpdateConversationRequestBodyInput", + "description": [], + "signature": [ + "{ id: string; title?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/crud_conversation_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.UpdateConversationRequestParams", + "type": "Type", + "tags": [], + "label": "UpdateConversationRequestParams", + "description": [], + "signature": [ + "{ id: string; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/crud_conversation_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.UpdateConversationRequestParamsInput", + "type": "Type", + "tags": [], + "label": "UpdateConversationRequestParamsInput", + "description": [], + "signature": [ + "{ id: string; }" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/crud_conversation_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.TraceData", + "id": "def-common.UpdateConversationResponse", "type": "Type", "tags": [], - "label": "TraceData", - "description": [ - "\ntrace Data" - ], + "label": "UpdateConversationResponse", + "description": [], "signature": [ - "{ transactionId?: string | undefined; traceId?: string | undefined; }" + "{ id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/crud_conversation_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.UpdateConversationRequestBody", + "id": "def-common.UpdateKnowledgeBaseEntryRequestBody", "type": "Type", "tags": [], - "label": "UpdateConversationRequestBody", + "label": "UpdateKnowledgeBaseEntryRequestBody", "description": [], "signature": [ - "{ id: string; title?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; }" + "{ id: string; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; }" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/crud_conversation_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_knowledge_base_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.UpdateConversationRequestBodyInput", + "id": "def-common.UpdateKnowledgeBaseEntryRequestBodyInput", "type": "Type", "tags": [], - "label": "UpdateConversationRequestBodyInput", + "label": "UpdateKnowledgeBaseEntryRequestBodyInput", "description": [], "signature": [ - "{ id: string; title?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; }" + "{ id: string; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; }" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/crud_conversation_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_knowledge_base_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.UpdateConversationRequestParams", + "id": "def-common.UpdateKnowledgeBaseEntryRequestParams", "type": "Type", "tags": [], - "label": "UpdateConversationRequestParams", + "label": "UpdateKnowledgeBaseEntryRequestParams", "description": [], "signature": [ "{ id: string; }" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/crud_conversation_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_knowledge_base_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.UpdateConversationRequestParamsInput", + "id": "def-common.UpdateKnowledgeBaseEntryRequestParamsInput", "type": "Type", "tags": [], - "label": "UpdateConversationRequestParamsInput", + "label": "UpdateKnowledgeBaseEntryRequestParamsInput", "description": [], "signature": [ "{ id: string; }" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/crud_conversation_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_knowledge_base_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.UpdateConversationResponse", + "id": "def-common.UpdateKnowledgeBaseEntryResponse", "type": "Type", "tags": [], - "label": "UpdateConversationResponse", + "label": "UpdateKnowledgeBaseEntryResponse", "description": [], "signature": [ - "{ id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }" + "{ id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/crud_conversation_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_knowledge_base_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -2267,7 +2838,7 @@ "signature": [ "{ id?: string | undefined; name?: string | undefined; }" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -2284,7 +2855,24 @@ "signature": [ "string" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.Vector", + "type": "Type", + "tags": [], + "label": "Vector", + "description": [ + "\nObject containing Knowledge Base Entry text embeddings and modelId used to create the embeddings" + ], + "signature": [ + "{ modelId: string; tokens: {} & { [k: string]: number; }; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/common_attributes.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -2406,7 +2994,7 @@ "label": "AppendConversationMessageResponse", "description": [], "signature": [ - "Zod.ZodObject<{ id: Zod.ZodUnion<[Zod.ZodString, Zod.ZodString]>; title: Zod.ZodString; category: Zod.ZodEnum<[\"assistant\", \"insights\"]>; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; timestamp: Zod.ZodOptional; updatedAt: Zod.ZodOptional; createdAt: Zod.ZodString; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; namespace: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }>" + "Zod.ZodObject<{ id: Zod.ZodString; title: Zod.ZodString; category: Zod.ZodEnum<[\"assistant\", \"insights\"]>; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; timestamp: Zod.ZodOptional; updatedAt: Zod.ZodOptional; createdAt: Zod.ZodString; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; namespace: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }>" ], "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/crud_conversation_route.gen.ts", "deprecated": false, @@ -2511,7 +3099,7 @@ "label": "BulkCrudActionResponse", "description": [], "signature": [ - "Zod.ZodObject<{ success: Zod.ZodOptional; status_code: Zod.ZodOptional; message: Zod.ZodOptional; conversations_count: Zod.ZodOptional; attributes: Zod.ZodObject<{ results: Zod.ZodObject<{ updated: Zod.ZodArray; title: Zod.ZodString; category: Zod.ZodEnum<[\"assistant\", \"insights\"]>; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; timestamp: Zod.ZodOptional; updatedAt: Zod.ZodOptional; createdAt: Zod.ZodString; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; namespace: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }>, \"many\">; created: Zod.ZodArray; title: Zod.ZodString; category: Zod.ZodEnum<[\"assistant\", \"insights\"]>; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; timestamp: Zod.ZodOptional; updatedAt: Zod.ZodOptional; createdAt: Zod.ZodString; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; namespace: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }>, \"many\">; deleted: Zod.ZodArray; skipped: Zod.ZodArray; skip_reason: Zod.ZodLiteral<\"CONVERSATION_NOT_MODIFIED\">; }, \"strip\", Zod.ZodTypeAny, { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }, { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }>, \"many\">; }, \"strip\", Zod.ZodTypeAny, { created: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; updated: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; skipped: { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }, { created: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; updated: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; skipped: { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }>; summary: Zod.ZodObject<{ failed: Zod.ZodNumber; skipped: Zod.ZodNumber; succeeded: Zod.ZodNumber; total: Zod.ZodNumber; }, \"strip\", Zod.ZodTypeAny, { total: number; succeeded: number; failed: number; skipped: number; }, { total: number; succeeded: number; failed: number; skipped: number; }>; errors: Zod.ZodOptional; conversations: Zod.ZodArray; }, \"strip\", Zod.ZodTypeAny, { id: string; name?: string | undefined; }, { id: string; name?: string | undefined; }>, \"many\">; }, \"strip\", Zod.ZodTypeAny, { message: string; status_code: number; conversations: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }, { message: string; status_code: number; conversations: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }>, \"many\">>; }, \"strip\", Zod.ZodTypeAny, { results: { created: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; updated: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; skipped: { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }; summary: { total: number; succeeded: number; failed: number; skipped: number; }; errors?: { message: string; status_code: number; conversations: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }[] | undefined; }, { results: { created: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; updated: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; skipped: { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }; summary: { total: number; succeeded: number; failed: number; skipped: number; }; errors?: { message: string; status_code: number; conversations: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }[] | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { attributes: { results: { created: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; updated: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; skipped: { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }; summary: { total: number; succeeded: number; failed: number; skipped: number; }; errors?: { message: string; status_code: number; conversations: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }[] | undefined; }; success?: boolean | undefined; status_code?: number | undefined; message?: string | undefined; conversations_count?: number | undefined; }, { attributes: { results: { created: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; updated: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; skipped: { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }; summary: { total: number; succeeded: number; failed: number; skipped: number; }; errors?: { message: string; status_code: number; conversations: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }[] | undefined; }; success?: boolean | undefined; status_code?: number | undefined; message?: string | undefined; conversations_count?: number | undefined; }>" + "Zod.ZodObject<{ success: Zod.ZodOptional; status_code: Zod.ZodOptional; message: Zod.ZodOptional; conversations_count: Zod.ZodOptional; attributes: Zod.ZodObject<{ results: Zod.ZodObject<{ updated: Zod.ZodArray; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; timestamp: Zod.ZodOptional; updatedAt: Zod.ZodOptional; createdAt: Zod.ZodString; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; namespace: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }>, \"many\">; created: Zod.ZodArray; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; timestamp: Zod.ZodOptional; updatedAt: Zod.ZodOptional; createdAt: Zod.ZodString; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; namespace: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }>, \"many\">; deleted: Zod.ZodArray; skipped: Zod.ZodArray; skip_reason: Zod.ZodLiteral<\"CONVERSATION_NOT_MODIFIED\">; }, \"strip\", Zod.ZodTypeAny, { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }, { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }>, \"many\">; }, \"strip\", Zod.ZodTypeAny, { created: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; updated: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; skipped: { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }, { created: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; updated: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; skipped: { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }>; summary: Zod.ZodObject<{ failed: Zod.ZodNumber; skipped: Zod.ZodNumber; succeeded: Zod.ZodNumber; total: Zod.ZodNumber; }, \"strip\", Zod.ZodTypeAny, { total: number; succeeded: number; failed: number; skipped: number; }, { total: number; succeeded: number; failed: number; skipped: number; }>; errors: Zod.ZodOptional; conversations: Zod.ZodArray; }, \"strip\", Zod.ZodTypeAny, { id: string; name?: string | undefined; }, { id: string; name?: string | undefined; }>, \"many\">; }, \"strip\", Zod.ZodTypeAny, { message: string; status_code: number; conversations: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }, { message: string; status_code: number; conversations: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }>, \"many\">>; }, \"strip\", Zod.ZodTypeAny, { results: { created: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; updated: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; skipped: { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }; summary: { total: number; succeeded: number; failed: number; skipped: number; }; errors?: { message: string; status_code: number; conversations: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }[] | undefined; }, { results: { created: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; updated: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; skipped: { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }; summary: { total: number; succeeded: number; failed: number; skipped: number; }; errors?: { message: string; status_code: number; conversations: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }[] | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { attributes: { results: { created: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; updated: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; skipped: { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }; summary: { total: number; succeeded: number; failed: number; skipped: number; }; errors?: { message: string; status_code: number; conversations: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }[] | undefined; }; success?: boolean | undefined; status_code?: number | undefined; message?: string | undefined; conversations_count?: number | undefined; }, { attributes: { results: { created: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; updated: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; skipped: { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }; summary: { total: number; succeeded: number; failed: number; skipped: number; }; errors?: { message: string; status_code: number; conversations: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }[] | undefined; }; success?: boolean | undefined; status_code?: number | undefined; message?: string | undefined; conversations_count?: number | undefined; }>" ], "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/bulk_crud_conversations_route.gen.ts", "deprecated": false, @@ -2526,7 +3114,7 @@ "label": "BulkCrudActionResults", "description": [], "signature": [ - "Zod.ZodObject<{ updated: Zod.ZodArray; title: Zod.ZodString; category: Zod.ZodEnum<[\"assistant\", \"insights\"]>; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; timestamp: Zod.ZodOptional; updatedAt: Zod.ZodOptional; createdAt: Zod.ZodString; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; namespace: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }>, \"many\">; created: Zod.ZodArray; title: Zod.ZodString; category: Zod.ZodEnum<[\"assistant\", \"insights\"]>; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; timestamp: Zod.ZodOptional; updatedAt: Zod.ZodOptional; createdAt: Zod.ZodString; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; namespace: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }>, \"many\">; deleted: Zod.ZodArray; skipped: Zod.ZodArray; skip_reason: Zod.ZodLiteral<\"CONVERSATION_NOT_MODIFIED\">; }, \"strip\", Zod.ZodTypeAny, { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }, { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }>, \"many\">; }, \"strip\", Zod.ZodTypeAny, { created: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; updated: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; skipped: { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }, { created: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; updated: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; skipped: { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }>" + "Zod.ZodObject<{ updated: Zod.ZodArray; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; timestamp: Zod.ZodOptional; updatedAt: Zod.ZodOptional; createdAt: Zod.ZodString; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; namespace: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }>, \"many\">; created: Zod.ZodArray; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; timestamp: Zod.ZodOptional; updatedAt: Zod.ZodOptional; createdAt: Zod.ZodString; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; namespace: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }>, \"many\">; deleted: Zod.ZodArray; skipped: Zod.ZodArray; skip_reason: Zod.ZodLiteral<\"CONVERSATION_NOT_MODIFIED\">; }, \"strip\", Zod.ZodTypeAny, { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }, { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }>, \"many\">; }, \"strip\", Zod.ZodTypeAny, { created: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; updated: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; skipped: { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }, { created: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; updated: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; skipped: { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }>" ], "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/bulk_crud_conversations_route.gen.ts", "deprecated": false, @@ -2661,7 +3249,7 @@ "label": "ConversationResponse", "description": [], "signature": [ - "Zod.ZodObject<{ id: Zod.ZodUnion<[Zod.ZodString, Zod.ZodString]>; title: Zod.ZodString; category: Zod.ZodEnum<[\"assistant\", \"insights\"]>; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; timestamp: Zod.ZodOptional; updatedAt: Zod.ZodOptional; createdAt: Zod.ZodString; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; namespace: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }>" + "Zod.ZodObject<{ id: Zod.ZodString; title: Zod.ZodString; category: Zod.ZodEnum<[\"assistant\", \"insights\"]>; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; timestamp: Zod.ZodOptional; updatedAt: Zod.ZodOptional; createdAt: Zod.ZodString; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; namespace: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }>" ], "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts", "deprecated": false, @@ -2691,356 +3279,581 @@ "label": "ConversationUpdateProps", "description": [], "signature": [ - "Zod.ZodObject<{ id: Zod.ZodUnion<[Zod.ZodString, Zod.ZodString]>; title: Zod.ZodOptional; category: Zod.ZodOptional>; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; excludeFromLastConversationStorage: Zod.ZodOptional; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; }, \"strip\", Zod.ZodTypeAny, { id: string; title?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; }, { id: string; title?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; }>" + "Zod.ZodObject<{ id: Zod.ZodString; title: Zod.ZodOptional; category: Zod.ZodOptional>; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; excludeFromLastConversationStorage: Zod.ZodOptional; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; }, \"strip\", Zod.ZodTypeAny, { id: string; title?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; }, { id: string; title?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; }>" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.CreateConversationRequestBody", + "type": "Object", + "tags": [], + "label": "CreateConversationRequestBody", + "description": [], + "signature": [ + "Zod.ZodObject<{ id: Zod.ZodOptional; title: Zod.ZodString; category: Zod.ZodOptional>; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; }, \"strip\", Zod.ZodTypeAny, { title: string; id?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; }, { title: string; id?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; }>" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/crud_conversation_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.CreateConversationResponse", + "type": "Object", + "tags": [], + "label": "CreateConversationResponse", + "description": [], + "signature": [ + "Zod.ZodObject<{ id: Zod.ZodString; title: Zod.ZodString; category: Zod.ZodEnum<[\"assistant\", \"insights\"]>; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; timestamp: Zod.ZodOptional; updatedAt: Zod.ZodOptional; createdAt: Zod.ZodString; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; namespace: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }>" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/crud_conversation_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.CreateKnowledgeBaseEntryRequestBody", + "type": "Object", + "tags": [], + "label": "CreateKnowledgeBaseEntryRequestBody", + "description": [], + "signature": [ + "Zod.ZodObject<{ metadata: Zod.ZodObject<{ kbResource: Zod.ZodString; source: Zod.ZodString; required: Zod.ZodBoolean; }, \"strip\", Zod.ZodTypeAny, { source: string; required: boolean; kbResource: string; }, { source: string; required: boolean; kbResource: string; }>; text: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { text: string; metadata: { source: string; required: boolean; kbResource: string; }; }, { text: string; metadata: { source: string; required: boolean; kbResource: string; }; }>" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_knowledge_base_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.CreateKnowledgeBaseEntryResponse", + "type": "Object", + "tags": [], + "label": "CreateKnowledgeBaseEntryResponse", + "description": [], + "signature": [ + "Zod.ZodObject<{ timestamp: Zod.ZodOptional; id: Zod.ZodString; createdAt: Zod.ZodString; createdBy: Zod.ZodOptional; updatedAt: Zod.ZodOptional; updatedBy: Zod.ZodOptional; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; metadata: Zod.ZodOptional>; namespace: Zod.ZodString; text: Zod.ZodString; vector: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodNumber, \"strip\">>; }, \"strip\", Zod.ZodTypeAny, { modelId: string; tokens: {} & { [k: string]: number; }; }, { modelId: string; tokens: {} & { [k: string]: number; }; }>>; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }, { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }>" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_knowledge_base_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.CreateKnowledgeBaseRequestParams", + "type": "Object", + "tags": [], + "label": "CreateKnowledgeBaseRequestParams", + "description": [], + "signature": [ + "Zod.ZodObject<{ resource: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { resource?: string | undefined; }, { resource?: string | undefined; }>" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.CreateKnowledgeBaseResponse", + "type": "Object", + "tags": [], + "label": "CreateKnowledgeBaseResponse", + "description": [], + "signature": [ + "Zod.ZodObject<{ success: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { success?: boolean | undefined; }, { success?: boolean | undefined; }>" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.Dataset", + "type": "Object", + "tags": [], + "label": "Dataset", + "description": [], + "signature": [ + "Zod.ZodDefault; input: Zod.ZodString; prediction: Zod.ZodOptional; reference: Zod.ZodString; tags: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { input: string; reference: string; id?: string | undefined; prediction?: string | undefined; tags?: string[] | undefined; }, { input: string; reference: string; id?: string | undefined; prediction?: string | undefined; tags?: string[] | undefined; }>, \"many\">>" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/evaluation/post_evaluate_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.DatasetItem", + "type": "Object", + "tags": [], + "label": "DatasetItem", + "description": [], + "signature": [ + "Zod.ZodObject<{ id: Zod.ZodOptional; input: Zod.ZodString; prediction: Zod.ZodOptional; reference: Zod.ZodString; tags: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { input: string; reference: string; id?: string | undefined; prediction?: string | undefined; tags?: string[] | undefined; }, { input: string; reference: string; id?: string | undefined; prediction?: string | undefined; tags?: string[] | undefined; }>" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/evaluation/post_evaluate_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.defaultAssistantFeatures", + "type": "Object", + "tags": [], + "label": "defaultAssistantFeatures", + "description": [ + "\nDefault features available to the elastic assistant" + ], + "signature": [ + "{ readonly assistantKnowledgeBaseByDefault: false; readonly assistantModelEvaluation: false; }" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/capabilities/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.DeleteConversationRequestParams", + "type": "Object", + "tags": [], + "label": "DeleteConversationRequestParams", + "description": [], + "signature": [ + "Zod.ZodObject<{ id: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; }, { id: string; }>" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/crud_conversation_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.DeleteConversationResponse", + "type": "Object", + "tags": [], + "label": "DeleteConversationResponse", + "description": [], + "signature": [ + "Zod.ZodObject<{ id: Zod.ZodString; title: Zod.ZodString; category: Zod.ZodEnum<[\"assistant\", \"insights\"]>; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; timestamp: Zod.ZodOptional; updatedAt: Zod.ZodOptional; createdAt: Zod.ZodString; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; namespace: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }>" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/crud_conversation_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.DeleteKnowledgeBaseEntryRequestParams", + "type": "Object", + "tags": [], + "label": "DeleteKnowledgeBaseEntryRequestParams", + "description": [], + "signature": [ + "Zod.ZodObject<{ id: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; }, { id: string; }>" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_knowledge_base_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.DeleteKnowledgeBaseEntryResponse", + "type": "Object", + "tags": [], + "label": "DeleteKnowledgeBaseEntryResponse", + "description": [], + "signature": [ + "Zod.ZodObject<{ timestamp: Zod.ZodOptional; id: Zod.ZodString; createdAt: Zod.ZodString; createdBy: Zod.ZodOptional; updatedAt: Zod.ZodOptional; updatedBy: Zod.ZodOptional; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; metadata: Zod.ZodOptional>; namespace: Zod.ZodString; text: Zod.ZodString; vector: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodNumber, \"strip\">>; }, \"strip\", Zod.ZodTypeAny, { modelId: string; tokens: {} & { [k: string]: number; }; }, { modelId: string; tokens: {} & { [k: string]: number; }; }>>; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }, { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }>" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_knowledge_base_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.DeleteKnowledgeBaseRequestParams", + "type": "Object", + "tags": [], + "label": "DeleteKnowledgeBaseRequestParams", + "description": [], + "signature": [ + "Zod.ZodObject<{ resource: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { resource?: string | undefined; }, { resource?: string | undefined; }>" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.DeleteKnowledgeBaseResponse", + "type": "Object", + "tags": [], + "label": "DeleteKnowledgeBaseResponse", + "description": [], + "signature": [ + "Zod.ZodObject<{ success: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { success?: boolean | undefined; }, { success?: boolean | undefined; }>" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.CreateConversationRequestBody", + "id": "def-common.ErrorSchema", "type": "Object", "tags": [], - "label": "CreateConversationRequestBody", + "label": "ErrorSchema", "description": [], "signature": [ - "Zod.ZodObject<{ id: Zod.ZodOptional; title: Zod.ZodString; category: Zod.ZodOptional>; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; }, \"strip\", Zod.ZodTypeAny, { title: string; id?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; }, { title: string; id?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; }>" + "Zod.ZodObject<{ id: Zod.ZodOptional; error: Zod.ZodObject<{ status_code: Zod.ZodNumber; message: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { message: string; status_code: number; }, { message: string; status_code: number; }>; }, \"strict\", Zod.ZodTypeAny, { error: { message: string; status_code: number; }; id?: string | undefined; }, { error: { message: string; status_code: number; }; id?: string | undefined; }>" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/crud_conversation_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.CreateConversationResponse", + "id": "def-common.ExecuteConnectorRequestBody", "type": "Object", "tags": [], - "label": "CreateConversationResponse", + "label": "ExecuteConnectorRequestBody", "description": [], "signature": [ - "Zod.ZodObject<{ id: Zod.ZodUnion<[Zod.ZodString, Zod.ZodString]>; title: Zod.ZodString; category: Zod.ZodEnum<[\"assistant\", \"insights\"]>; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; timestamp: Zod.ZodOptional; updatedAt: Zod.ZodOptional; createdAt: Zod.ZodString; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; namespace: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | 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>; 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; }>" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/crud_conversation_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/actions_connector/post_actions_connector_execute_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.CreateKnowledgeBaseRequestParams", + "id": "def-common.ExecuteConnectorRequestParams", "type": "Object", "tags": [], - "label": "CreateKnowledgeBaseRequestParams", + "label": "ExecuteConnectorRequestParams", "description": [], "signature": [ - "Zod.ZodObject<{ resource: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { resource?: string | undefined; }, { resource?: string | undefined; }>" + "Zod.ZodObject<{ connectorId: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; }, { connectorId: string; }>" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/actions_connector/post_actions_connector_execute_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.CreateKnowledgeBaseResponse", + "id": "def-common.ExecuteConnectorResponse", "type": "Object", "tags": [], - "label": "CreateKnowledgeBaseResponse", + "label": "ExecuteConnectorResponse", "description": [], "signature": [ - "Zod.ZodObject<{ success: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { success?: boolean | undefined; }, { success?: boolean | undefined; }>" + "Zod.ZodObject<{ data: Zod.ZodString; connector_id: Zod.ZodString; status: Zod.ZodString; trace_data: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { status: string; data: string; connector_id: string; trace_data?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { status: string; data: string; connector_id: string; trace_data?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/actions_connector/post_actions_connector_execute_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.Dataset", + "id": "def-common.FindConversationsRequestQuery", "type": "Object", "tags": [], - "label": "Dataset", + "label": "FindConversationsRequestQuery", "description": [], "signature": [ - "Zod.ZodDefault; input: Zod.ZodString; prediction: Zod.ZodOptional; reference: Zod.ZodString; tags: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { input: string; reference: string; id?: string | undefined; prediction?: string | undefined; tags?: string[] | undefined; }, { input: string; reference: string; id?: string | undefined; prediction?: string | undefined; tags?: string[] | undefined; }>, \"many\">>" + "Zod.ZodObject<{ fields: Zod.ZodOptional, string[], unknown>>; filter: Zod.ZodOptional; sort_field: Zod.ZodOptional>; sort_order: Zod.ZodOptional>; page: Zod.ZodDefault>; per_page: Zod.ZodDefault>; }, \"strip\", Zod.ZodTypeAny, { per_page: number; page: number; fields?: string[] | undefined; filter?: string | undefined; sort_field?: \"title\" | \"updated_at\" | \"created_at\" | \"is_default\" | undefined; sort_order?: \"asc\" | \"desc\" | undefined; }, { fields?: unknown; filter?: string | undefined; sort_field?: \"title\" | \"updated_at\" | \"created_at\" | \"is_default\" | undefined; sort_order?: \"asc\" | \"desc\" | undefined; page?: number | undefined; per_page?: number | undefined; }>" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/evaluation/post_evaluate_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.DatasetItem", + "id": "def-common.FindConversationsResponse", "type": "Object", "tags": [], - "label": "DatasetItem", + "label": "FindConversationsResponse", "description": [], "signature": [ - "Zod.ZodObject<{ id: Zod.ZodOptional; input: Zod.ZodString; prediction: Zod.ZodOptional; reference: Zod.ZodString; tags: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { input: string; reference: string; id?: string | undefined; prediction?: string | undefined; tags?: string[] | undefined; }, { input: string; reference: string; id?: string | undefined; prediction?: string | undefined; tags?: string[] | undefined; }>" + "Zod.ZodObject<{ page: Zod.ZodNumber; perPage: Zod.ZodNumber; total: Zod.ZodNumber; data: Zod.ZodArray; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; timestamp: Zod.ZodOptional; updatedAt: Zod.ZodOptional; createdAt: Zod.ZodString; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; namespace: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }>, \"many\">; }, \"strip\", Zod.ZodTypeAny, { page: number; perPage: number; total: number; data: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; }, { page: number; perPage: number; total: number; data: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; }>" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/evaluation/post_evaluate_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.defaultAssistantFeatures", + "id": "def-common.FindConversationsSortField", "type": "Object", "tags": [], - "label": "defaultAssistantFeatures", - "description": [ - "\nDefault features available to the elastic assistant" - ], + "label": "FindConversationsSortField", + "description": [], "signature": [ - "{ readonly assistantModelEvaluation: false; }" + "Zod.ZodEnum<[\"created_at\", \"is_default\", \"title\", \"updated_at\"]>" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/capabilities/index.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.DeleteConversationRequestParams", + "id": "def-common.FindConversationsSortFieldEnum", "type": "Object", "tags": [], - "label": "DeleteConversationRequestParams", + "label": "FindConversationsSortFieldEnum", "description": [], "signature": [ - "Zod.ZodObject<{ id: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; }, { id: string; }>" + "{ title: \"title\"; updated_at: \"updated_at\"; created_at: \"created_at\"; is_default: \"is_default\"; }" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/crud_conversation_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.DeleteConversationResponse", + "id": "def-common.FindCurrentUserConversationsRequestQuery", "type": "Object", "tags": [], - "label": "DeleteConversationResponse", + "label": "FindCurrentUserConversationsRequestQuery", "description": [], "signature": [ - "Zod.ZodObject<{ id: Zod.ZodUnion<[Zod.ZodString, Zod.ZodString]>; title: Zod.ZodString; category: Zod.ZodEnum<[\"assistant\", \"insights\"]>; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; timestamp: Zod.ZodOptional; updatedAt: Zod.ZodOptional; createdAt: Zod.ZodString; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; namespace: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }>" + "Zod.ZodObject<{ fields: Zod.ZodOptional, string[], unknown>>; filter: Zod.ZodOptional; sort_field: Zod.ZodOptional>; sort_order: Zod.ZodOptional>; page: Zod.ZodDefault>; per_page: Zod.ZodDefault>; }, \"strip\", Zod.ZodTypeAny, { per_page: number; page: number; fields?: string[] | undefined; filter?: string | undefined; sort_field?: \"title\" | \"updated_at\" | \"created_at\" | \"is_default\" | undefined; sort_order?: \"asc\" | \"desc\" | undefined; }, { fields?: unknown; filter?: string | undefined; sort_field?: \"title\" | \"updated_at\" | \"created_at\" | \"is_default\" | undefined; sort_order?: \"asc\" | \"desc\" | undefined; page?: number | undefined; per_page?: number | undefined; }>" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/crud_conversation_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.DeleteKnowledgeBaseRequestParams", + "id": "def-common.FindCurrentUserConversationsResponse", "type": "Object", "tags": [], - "label": "DeleteKnowledgeBaseRequestParams", + "label": "FindCurrentUserConversationsResponse", "description": [], "signature": [ - "Zod.ZodObject<{ resource: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { resource?: string | undefined; }, { resource?: string | undefined; }>" + "Zod.ZodObject<{ page: Zod.ZodNumber; perPage: Zod.ZodNumber; total: Zod.ZodNumber; data: Zod.ZodArray; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; timestamp: Zod.ZodOptional; updatedAt: Zod.ZodOptional; createdAt: Zod.ZodString; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; namespace: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }>, \"many\">; }, \"strip\", Zod.ZodTypeAny, { page: number; perPage: number; total: number; data: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; }, { page: number; perPage: number; total: number; data: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; }>" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.DeleteKnowledgeBaseResponse", + "id": "def-common.GetCapabilitiesResponse", "type": "Object", "tags": [], - "label": "DeleteKnowledgeBaseResponse", + "label": "GetCapabilitiesResponse", "description": [], "signature": [ - "Zod.ZodObject<{ success: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { success?: boolean | undefined; }, { success?: boolean | undefined; }>" + "Zod.ZodObject<{ assistantKnowledgeBaseByDefault: Zod.ZodBoolean; assistantModelEvaluation: Zod.ZodBoolean; }, \"strip\", Zod.ZodTypeAny, { assistantKnowledgeBaseByDefault: boolean; assistantModelEvaluation: boolean; }, { assistantKnowledgeBaseByDefault: boolean; assistantModelEvaluation: boolean; }>" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/capabilities/get_capabilities_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.ErrorSchema", + "id": "def-common.GetEvaluateResponse", "type": "Object", "tags": [], - "label": "ErrorSchema", + "label": "GetEvaluateResponse", "description": [], "signature": [ - "Zod.ZodObject<{ id: Zod.ZodOptional; error: Zod.ZodObject<{ status_code: Zod.ZodNumber; message: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { message: string; status_code: number; }, { message: string; status_code: number; }>; }, \"strict\", Zod.ZodTypeAny, { error: { message: string; status_code: number; }; id?: string | undefined; }, { error: { message: string; status_code: number; }; id?: string | undefined; }>" + "Zod.ZodObject<{ agentExecutors: Zod.ZodArray; }, \"strip\", Zod.ZodTypeAny, { agentExecutors: string[]; }, { agentExecutors: string[]; }>" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/evaluation/get_evaluate_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.ExecuteConnectorRequestBody", + "id": "def-common.KnowledgeBaseEntryBulkActionBase", "type": "Object", "tags": [], - "label": "ExecuteConnectorRequestBody", + "label": "KnowledgeBaseEntryBulkActionBase", "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<{ query: Zod.ZodOptional; ids: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { query?: string | undefined; ids?: string[] | undefined; }, { query?: string | undefined; ids?: string[] | undefined; }>" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/actions_connector/post_actions_connector_execute_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/bulk_crud_knowledge_base_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.ExecuteConnectorRequestParams", + "id": "def-common.KnowledgeBaseEntryBulkActionSkipReason", "type": "Object", "tags": [], - "label": "ExecuteConnectorRequestParams", + "label": "KnowledgeBaseEntryBulkActionSkipReason", "description": [], "signature": [ - "Zod.ZodObject<{ connectorId: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; }, { connectorId: string; }>" + "Zod.ZodLiteral<\"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\">" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/actions_connector/post_actions_connector_execute_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/bulk_crud_knowledge_base_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.ExecuteConnectorResponse", + "id": "def-common.KnowledgeBaseEntryBulkActionSkipResult", "type": "Object", "tags": [], - "label": "ExecuteConnectorResponse", + "label": "KnowledgeBaseEntryBulkActionSkipResult", "description": [], "signature": [ - "Zod.ZodObject<{ data: Zod.ZodString; connector_id: Zod.ZodString; status: Zod.ZodString; trace_data: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { status: string; data: string; connector_id: string; trace_data?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { status: string; data: string; connector_id: string; trace_data?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>" + "Zod.ZodObject<{ id: Zod.ZodString; name: Zod.ZodOptional; skip_reason: Zod.ZodLiteral<\"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\">; }, \"strip\", Zod.ZodTypeAny, { id: string; skip_reason: \"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\"; name?: string | undefined; }, { id: string; skip_reason: \"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\"; name?: string | undefined; }>" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/actions_connector/post_actions_connector_execute_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/bulk_crud_knowledge_base_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.FindConversationsRequestQuery", + "id": "def-common.KnowledgeBaseEntryBulkCrudActionResponse", "type": "Object", "tags": [], - "label": "FindConversationsRequestQuery", + "label": "KnowledgeBaseEntryBulkCrudActionResponse", "description": [], "signature": [ - "Zod.ZodObject<{ fields: Zod.ZodOptional, string[], unknown>>; filter: Zod.ZodOptional; sort_field: Zod.ZodOptional>; sort_order: Zod.ZodOptional>; page: Zod.ZodDefault>; per_page: Zod.ZodDefault>; }, \"strip\", Zod.ZodTypeAny, { per_page: number; page: number; fields?: string[] | undefined; filter?: string | undefined; sort_field?: \"title\" | \"updated_at\" | \"created_at\" | \"is_default\" | undefined; sort_order?: \"asc\" | \"desc\" | undefined; }, { fields?: unknown; filter?: string | undefined; sort_field?: \"title\" | \"updated_at\" | \"created_at\" | \"is_default\" | undefined; sort_order?: \"asc\" | \"desc\" | undefined; page?: number | undefined; per_page?: number | undefined; }>" + "Zod.ZodObject<{ success: Zod.ZodOptional; statusCode: Zod.ZodOptional; message: Zod.ZodOptional; knowledgeBaseEntriesCount: Zod.ZodOptional; attributes: Zod.ZodObject<{ results: Zod.ZodObject<{ updated: Zod.ZodArray; id: Zod.ZodString; createdAt: Zod.ZodString; createdBy: Zod.ZodOptional; updatedAt: Zod.ZodOptional; updatedBy: Zod.ZodOptional; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; metadata: Zod.ZodOptional>; namespace: Zod.ZodString; text: Zod.ZodString; vector: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodNumber, \"strip\">>; }, \"strip\", Zod.ZodTypeAny, { modelId: string; tokens: {} & { [k: string]: number; }; }, { modelId: string; tokens: {} & { [k: string]: number; }; }>>; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }, { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }>, \"many\">; created: Zod.ZodArray; id: Zod.ZodString; createdAt: Zod.ZodString; createdBy: Zod.ZodOptional; updatedAt: Zod.ZodOptional; updatedBy: Zod.ZodOptional; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; metadata: Zod.ZodOptional>; namespace: Zod.ZodString; text: Zod.ZodString; vector: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodNumber, \"strip\">>; }, \"strip\", Zod.ZodTypeAny, { modelId: string; tokens: {} & { [k: string]: number; }; }, { modelId: string; tokens: {} & { [k: string]: number; }; }>>; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }, { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }>, \"many\">; deleted: Zod.ZodArray; skipped: Zod.ZodArray; skip_reason: Zod.ZodLiteral<\"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\">; }, \"strip\", Zod.ZodTypeAny, { id: string; skip_reason: \"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\"; name?: string | undefined; }, { id: string; skip_reason: \"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\"; name?: string | undefined; }>, \"many\">; }, \"strip\", Zod.ZodTypeAny, { created: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; updated: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; skipped: { id: string; skip_reason: \"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }, { created: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; updated: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; skipped: { id: string; skip_reason: \"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }>; summary: Zod.ZodObject<{ failed: Zod.ZodNumber; skipped: Zod.ZodNumber; succeeded: Zod.ZodNumber; total: Zod.ZodNumber; }, \"strip\", Zod.ZodTypeAny, { total: number; succeeded: number; failed: number; skipped: number; }, { total: number; succeeded: number; failed: number; skipped: number; }>; errors: Zod.ZodOptional; knowledgeBaseEntries: Zod.ZodArray; }, \"strip\", Zod.ZodTypeAny, { id: string; name?: string | undefined; }, { id: string; name?: string | undefined; }>, \"many\">; }, \"strip\", Zod.ZodTypeAny, { message: string; statusCode: number; knowledgeBaseEntries: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }, { message: string; statusCode: number; knowledgeBaseEntries: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }>, \"many\">>; }, \"strip\", Zod.ZodTypeAny, { results: { created: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; updated: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; skipped: { id: string; skip_reason: \"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }; summary: { total: number; succeeded: number; failed: number; skipped: number; }; errors?: { message: string; statusCode: number; knowledgeBaseEntries: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }[] | undefined; }, { results: { created: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; updated: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; skipped: { id: string; skip_reason: \"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }; summary: { total: number; succeeded: number; failed: number; skipped: number; }; errors?: { message: string; statusCode: number; knowledgeBaseEntries: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }[] | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { attributes: { results: { created: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; updated: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; skipped: { id: string; skip_reason: \"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }; summary: { total: number; succeeded: number; failed: number; skipped: number; }; errors?: { message: string; statusCode: number; knowledgeBaseEntries: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }[] | undefined; }; success?: boolean | undefined; statusCode?: number | undefined; message?: string | undefined; knowledgeBaseEntriesCount?: number | undefined; }, { attributes: { results: { created: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; updated: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; skipped: { id: string; skip_reason: \"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }; summary: { total: number; succeeded: number; failed: number; skipped: number; }; errors?: { message: string; statusCode: number; knowledgeBaseEntries: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }[] | undefined; }; success?: boolean | undefined; statusCode?: number | undefined; message?: string | undefined; knowledgeBaseEntriesCount?: number | undefined; }>" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/bulk_crud_knowledge_base_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.FindConversationsResponse", + "id": "def-common.KnowledgeBaseEntryBulkCrudActionResults", "type": "Object", "tags": [], - "label": "FindConversationsResponse", + "label": "KnowledgeBaseEntryBulkCrudActionResults", "description": [], "signature": [ - "Zod.ZodObject<{ page: Zod.ZodNumber; perPage: Zod.ZodNumber; total: Zod.ZodNumber; data: Zod.ZodArray; title: Zod.ZodString; category: Zod.ZodEnum<[\"assistant\", \"insights\"]>; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; timestamp: Zod.ZodOptional; updatedAt: Zod.ZodOptional; createdAt: Zod.ZodString; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; namespace: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }>, \"many\">; }, \"strip\", Zod.ZodTypeAny, { page: number; perPage: number; total: number; data: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; }, { page: number; perPage: number; total: number; data: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; }>" + "Zod.ZodObject<{ updated: Zod.ZodArray; id: Zod.ZodString; createdAt: Zod.ZodString; createdBy: Zod.ZodOptional; updatedAt: Zod.ZodOptional; updatedBy: Zod.ZodOptional; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; metadata: Zod.ZodOptional>; namespace: Zod.ZodString; text: Zod.ZodString; vector: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodNumber, \"strip\">>; }, \"strip\", Zod.ZodTypeAny, { modelId: string; tokens: {} & { [k: string]: number; }; }, { modelId: string; tokens: {} & { [k: string]: number; }; }>>; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }, { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }>, \"many\">; created: Zod.ZodArray; id: Zod.ZodString; createdAt: Zod.ZodString; createdBy: Zod.ZodOptional; updatedAt: Zod.ZodOptional; updatedBy: Zod.ZodOptional; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; metadata: Zod.ZodOptional>; namespace: Zod.ZodString; text: Zod.ZodString; vector: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodNumber, \"strip\">>; }, \"strip\", Zod.ZodTypeAny, { modelId: string; tokens: {} & { [k: string]: number; }; }, { modelId: string; tokens: {} & { [k: string]: number; }; }>>; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }, { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }>, \"many\">; deleted: Zod.ZodArray; skipped: Zod.ZodArray; skip_reason: Zod.ZodLiteral<\"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\">; }, \"strip\", Zod.ZodTypeAny, { id: string; skip_reason: \"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\"; name?: string | undefined; }, { id: string; skip_reason: \"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\"; name?: string | undefined; }>, \"many\">; }, \"strip\", Zod.ZodTypeAny, { created: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; updated: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; skipped: { id: string; skip_reason: \"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }, { created: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; updated: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; skipped: { id: string; skip_reason: \"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }>" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/bulk_crud_knowledge_base_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.FindConversationsSortField", + "id": "def-common.KnowledgeBaseEntryBulkCrudActionSummary", "type": "Object", "tags": [], - "label": "FindConversationsSortField", + "label": "KnowledgeBaseEntryBulkCrudActionSummary", "description": [], "signature": [ - "Zod.ZodEnum<[\"created_at\", \"is_default\", \"title\", \"updated_at\"]>" + "Zod.ZodObject<{ failed: Zod.ZodNumber; skipped: Zod.ZodNumber; succeeded: Zod.ZodNumber; total: Zod.ZodNumber; }, \"strip\", Zod.ZodTypeAny, { total: number; succeeded: number; failed: number; skipped: number; }, { total: number; succeeded: number; failed: number; skipped: number; }>" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/bulk_crud_knowledge_base_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.FindConversationsSortFieldEnum", + "id": "def-common.KnowledgeBaseEntryCreateProps", "type": "Object", "tags": [], - "label": "FindConversationsSortFieldEnum", + "label": "KnowledgeBaseEntryCreateProps", "description": [], "signature": [ - "{ title: \"title\"; updated_at: \"updated_at\"; created_at: \"created_at\"; is_default: \"is_default\"; }" + "Zod.ZodObject<{ metadata: Zod.ZodObject<{ kbResource: Zod.ZodString; source: Zod.ZodString; required: Zod.ZodBoolean; }, \"strip\", Zod.ZodTypeAny, { source: string; required: boolean; kbResource: string; }, { source: string; required: boolean; kbResource: string; }>; text: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { text: string; metadata: { source: string; required: boolean; kbResource: string; }; }, { text: string; metadata: { source: string; required: boolean; kbResource: string; }; }>" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/common_attributes.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.FindCurrentUserConversationsRequestQuery", + "id": "def-common.KnowledgeBaseEntryDetailsInError", "type": "Object", "tags": [], - "label": "FindCurrentUserConversationsRequestQuery", + "label": "KnowledgeBaseEntryDetailsInError", "description": [], "signature": [ - "Zod.ZodObject<{ fields: Zod.ZodOptional, string[], unknown>>; filter: Zod.ZodOptional; sort_field: Zod.ZodOptional>; sort_order: Zod.ZodOptional>; page: Zod.ZodDefault>; per_page: Zod.ZodDefault>; }, \"strip\", Zod.ZodTypeAny, { per_page: number; page: number; fields?: string[] | undefined; filter?: string | undefined; sort_field?: \"title\" | \"updated_at\" | \"created_at\" | \"is_default\" | undefined; sort_order?: \"asc\" | \"desc\" | undefined; }, { fields?: unknown; filter?: string | undefined; sort_field?: \"title\" | \"updated_at\" | \"created_at\" | \"is_default\" | undefined; sort_order?: \"asc\" | \"desc\" | undefined; page?: number | undefined; per_page?: number | undefined; }>" + "Zod.ZodObject<{ id: Zod.ZodString; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id: string; name?: string | undefined; }, { id: string; name?: string | undefined; }>" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/bulk_crud_knowledge_base_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.FindCurrentUserConversationsResponse", + "id": "def-common.KnowledgeBaseEntryErrorSchema", "type": "Object", "tags": [], - "label": "FindCurrentUserConversationsResponse", + "label": "KnowledgeBaseEntryErrorSchema", "description": [], "signature": [ - "Zod.ZodObject<{ page: Zod.ZodNumber; perPage: Zod.ZodNumber; total: Zod.ZodNumber; data: Zod.ZodArray; title: Zod.ZodString; category: Zod.ZodEnum<[\"assistant\", \"insights\"]>; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; timestamp: Zod.ZodOptional; updatedAt: Zod.ZodOptional; createdAt: Zod.ZodString; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; namespace: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }>, \"many\">; }, \"strip\", Zod.ZodTypeAny, { page: number; perPage: number; total: number; data: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; }, { page: number; perPage: number; total: number; data: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; }>" + "Zod.ZodObject<{ statusCode: Zod.ZodNumber; error: Zod.ZodString; message: Zod.ZodString; }, \"strict\", Zod.ZodTypeAny, { error: string; message: string; statusCode: number; }, { error: string; message: string; statusCode: number; }>" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/common_attributes.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.GetCapabilitiesResponse", + "id": "def-common.KnowledgeBaseEntryResponse", "type": "Object", "tags": [], - "label": "GetCapabilitiesResponse", + "label": "KnowledgeBaseEntryResponse", "description": [], "signature": [ - "Zod.ZodObject<{ assistantModelEvaluation: Zod.ZodBoolean; }, \"strip\", Zod.ZodTypeAny, { assistantModelEvaluation: boolean; }, { assistantModelEvaluation: boolean; }>" + "Zod.ZodObject<{ timestamp: Zod.ZodOptional; id: Zod.ZodString; createdAt: Zod.ZodString; createdBy: Zod.ZodOptional; updatedAt: Zod.ZodOptional; updatedBy: Zod.ZodOptional; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; metadata: Zod.ZodOptional>; namespace: Zod.ZodString; text: Zod.ZodString; vector: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodNumber, \"strip\">>; }, \"strip\", Zod.ZodTypeAny, { modelId: string; tokens: {} & { [k: string]: number; }; }, { modelId: string; tokens: {} & { [k: string]: number; }; }>>; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }, { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }>" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/capabilities/get_capabilities_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/common_attributes.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "@kbn/elastic-assistant-common", - "id": "def-common.GetEvaluateResponse", + "id": "def-common.KnowledgeBaseEntryUpdateProps", "type": "Object", "tags": [], - "label": "GetEvaluateResponse", + "label": "KnowledgeBaseEntryUpdateProps", "description": [], "signature": [ - "Zod.ZodObject<{ agentExecutors: Zod.ZodArray; }, \"strip\", Zod.ZodTypeAny, { agentExecutors: string[]; }, { agentExecutors: string[]; }>" + "Zod.ZodObject<{ id: Zod.ZodString; metadata: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { id: string; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; }, { id: string; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; }>" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/evaluation/get_evaluate_route.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/common_attributes.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -3105,6 +3918,21 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.Metadata", + "type": "Object", + "tags": [], + "label": "Metadata", + "description": [], + "signature": [ + "Zod.ZodObject<{ kbResource: Zod.ZodString; source: Zod.ZodString; required: Zod.ZodBoolean; }, \"strip\", Zod.ZodTypeAny, { source: string; required: boolean; kbResource: string; }, { source: string; required: boolean; kbResource: string; }>" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/common_attributes.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/elastic-assistant-common", "id": "def-common.NonEmptyString", @@ -3115,7 +3943,7 @@ "signature": [ "Zod.ZodString" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -3135,6 +3963,21 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.NormalizedKnowledgeBaseEntryError", + "type": "Object", + "tags": [], + "label": "NormalizedKnowledgeBaseEntryError", + "description": [], + "signature": [ + "Zod.ZodObject<{ message: Zod.ZodString; statusCode: Zod.ZodNumber; err_code: Zod.ZodOptional; knowledgeBaseEntries: Zod.ZodArray; }, \"strip\", Zod.ZodTypeAny, { id: string; name?: string | undefined; }, { id: string; name?: string | undefined; }>, \"many\">; }, \"strip\", Zod.ZodTypeAny, { message: string; statusCode: number; knowledgeBaseEntries: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }, { message: string; statusCode: number; knowledgeBaseEntries: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }>" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/bulk_crud_knowledge_base_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/elastic-assistant-common", "id": "def-common.OutputIndex", @@ -3158,7 +4001,7 @@ "label": "PerformBulkActionRequestBody", "description": [], "signature": [ - "Zod.ZodObject<{ delete: Zod.ZodOptional; ids: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { query?: string | undefined; ids?: string[] | undefined; }, { query?: string | undefined; ids?: string[] | undefined; }>>; create: Zod.ZodOptional; title: Zod.ZodString; category: Zod.ZodOptional>; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; }, \"strip\", Zod.ZodTypeAny, { title: string; id?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; }, { title: string; id?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; }>, \"many\">>; update: Zod.ZodOptional; title: Zod.ZodOptional; category: Zod.ZodOptional>; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; excludeFromLastConversationStorage: Zod.ZodOptional; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; }, \"strip\", Zod.ZodTypeAny, { id: string; title?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; }, { id: string; title?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; }>, \"many\">>; }, \"strip\", Zod.ZodTypeAny, { delete?: { query?: string | undefined; ids?: string[] | undefined; } | undefined; create?: { title: string; id?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; }[] | undefined; update?: { id: string; title?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; }[] | undefined; }, { delete?: { query?: string | undefined; ids?: string[] | undefined; } | undefined; create?: { title: string; id?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; }[] | undefined; update?: { id: string; title?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; }[] | undefined; }>" + "Zod.ZodObject<{ delete: Zod.ZodOptional; ids: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { query?: string | undefined; ids?: string[] | undefined; }, { query?: string | undefined; ids?: string[] | undefined; }>>; create: Zod.ZodOptional; title: Zod.ZodString; category: Zod.ZodOptional>; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; }, \"strip\", Zod.ZodTypeAny, { title: string; id?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; }, { title: string; id?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; }>, \"many\">>; update: Zod.ZodOptional; category: Zod.ZodOptional>; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; excludeFromLastConversationStorage: Zod.ZodOptional; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; }, \"strip\", Zod.ZodTypeAny, { id: string; title?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; }, { id: string; title?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; }>, \"many\">>; }, \"strip\", Zod.ZodTypeAny, { delete?: { query?: string | undefined; ids?: string[] | undefined; } | undefined; create?: { title: string; id?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; }[] | undefined; update?: { id: string; title?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; }[] | undefined; }, { delete?: { query?: string | undefined; ids?: string[] | undefined; } | undefined; create?: { title: string; id?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; }[] | undefined; update?: { id: string; title?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; }[] | undefined; }>" ], "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/bulk_crud_conversations_route.gen.ts", "deprecated": false, @@ -3173,13 +4016,43 @@ "label": "PerformBulkActionResponse", "description": [], "signature": [ - "Zod.ZodObject<{ success: Zod.ZodOptional; status_code: Zod.ZodOptional; message: Zod.ZodOptional; conversations_count: Zod.ZodOptional; attributes: Zod.ZodObject<{ results: Zod.ZodObject<{ updated: Zod.ZodArray; title: Zod.ZodString; category: Zod.ZodEnum<[\"assistant\", \"insights\"]>; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; timestamp: Zod.ZodOptional; updatedAt: Zod.ZodOptional; createdAt: Zod.ZodString; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; namespace: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }>, \"many\">; created: Zod.ZodArray; title: Zod.ZodString; category: Zod.ZodEnum<[\"assistant\", \"insights\"]>; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; timestamp: Zod.ZodOptional; updatedAt: Zod.ZodOptional; createdAt: Zod.ZodString; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; namespace: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }>, \"many\">; deleted: Zod.ZodArray; skipped: Zod.ZodArray; skip_reason: Zod.ZodLiteral<\"CONVERSATION_NOT_MODIFIED\">; }, \"strip\", Zod.ZodTypeAny, { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }, { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }>, \"many\">; }, \"strip\", Zod.ZodTypeAny, { created: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; updated: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; skipped: { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }, { created: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; updated: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; skipped: { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }>; summary: Zod.ZodObject<{ failed: Zod.ZodNumber; skipped: Zod.ZodNumber; succeeded: Zod.ZodNumber; total: Zod.ZodNumber; }, \"strip\", Zod.ZodTypeAny, { total: number; succeeded: number; failed: number; skipped: number; }, { total: number; succeeded: number; failed: number; skipped: number; }>; errors: Zod.ZodOptional; conversations: Zod.ZodArray; }, \"strip\", Zod.ZodTypeAny, { id: string; name?: string | undefined; }, { id: string; name?: string | undefined; }>, \"many\">; }, \"strip\", Zod.ZodTypeAny, { message: string; status_code: number; conversations: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }, { message: string; status_code: number; conversations: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }>, \"many\">>; }, \"strip\", Zod.ZodTypeAny, { results: { created: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; updated: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; skipped: { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }; summary: { total: number; succeeded: number; failed: number; skipped: number; }; errors?: { message: string; status_code: number; conversations: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }[] | undefined; }, { results: { created: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; updated: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; skipped: { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }; summary: { total: number; succeeded: number; failed: number; skipped: number; }; errors?: { message: string; status_code: number; conversations: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }[] | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { attributes: { results: { created: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; updated: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; skipped: { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }; summary: { total: number; succeeded: number; failed: number; skipped: number; }; errors?: { message: string; status_code: number; conversations: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }[] | undefined; }; success?: boolean | undefined; status_code?: number | undefined; message?: string | undefined; conversations_count?: number | undefined; }, { attributes: { results: { created: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; updated: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; skipped: { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }; summary: { total: number; succeeded: number; failed: number; skipped: number; }; errors?: { message: string; status_code: number; conversations: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }[] | undefined; }; success?: boolean | undefined; status_code?: number | undefined; message?: string | undefined; conversations_count?: number | undefined; }>" + "Zod.ZodObject<{ success: Zod.ZodOptional; status_code: Zod.ZodOptional; message: Zod.ZodOptional; conversations_count: Zod.ZodOptional; attributes: Zod.ZodObject<{ results: Zod.ZodObject<{ updated: Zod.ZodArray; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; timestamp: Zod.ZodOptional; updatedAt: Zod.ZodOptional; createdAt: Zod.ZodString; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; namespace: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }>, \"many\">; created: Zod.ZodArray; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; timestamp: Zod.ZodOptional; updatedAt: Zod.ZodOptional; createdAt: Zod.ZodString; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; namespace: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }>, \"many\">; deleted: Zod.ZodArray; skipped: Zod.ZodArray; skip_reason: Zod.ZodLiteral<\"CONVERSATION_NOT_MODIFIED\">; }, \"strip\", Zod.ZodTypeAny, { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }, { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }>, \"many\">; }, \"strip\", Zod.ZodTypeAny, { created: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; updated: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; skipped: { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }, { created: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; updated: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; skipped: { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }>; summary: Zod.ZodObject<{ failed: Zod.ZodNumber; skipped: Zod.ZodNumber; succeeded: Zod.ZodNumber; total: Zod.ZodNumber; }, \"strip\", Zod.ZodTypeAny, { total: number; succeeded: number; failed: number; skipped: number; }, { total: number; succeeded: number; failed: number; skipped: number; }>; errors: Zod.ZodOptional; conversations: Zod.ZodArray; }, \"strip\", Zod.ZodTypeAny, { id: string; name?: string | undefined; }, { id: string; name?: string | undefined; }>, \"many\">; }, \"strip\", Zod.ZodTypeAny, { message: string; status_code: number; conversations: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }, { message: string; status_code: number; conversations: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }>, \"many\">>; }, \"strip\", Zod.ZodTypeAny, { results: { created: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; updated: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; skipped: { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }; summary: { total: number; succeeded: number; failed: number; skipped: number; }; errors?: { message: string; status_code: number; conversations: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }[] | undefined; }, { results: { created: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; updated: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; skipped: { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }; summary: { total: number; succeeded: number; failed: number; skipped: number; }; errors?: { message: string; status_code: number; conversations: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }[] | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { attributes: { results: { created: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; updated: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; skipped: { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }; summary: { total: number; succeeded: number; failed: number; skipped: number; }; errors?: { message: string; status_code: number; conversations: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }[] | undefined; }; success?: boolean | undefined; status_code?: number | undefined; message?: string | undefined; conversations_count?: number | undefined; }, { attributes: { results: { created: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; updated: { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }[]; skipped: { id: string; skip_reason: \"CONVERSATION_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }; summary: { total: number; succeeded: number; failed: number; skipped: number; }; errors?: { message: string; status_code: number; conversations: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }[] | undefined; }; success?: boolean | undefined; status_code?: number | undefined; message?: string | undefined; conversations_count?: number | undefined; }>" ], "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/bulk_crud_conversations_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.PerformKnowledgeBaseEntryBulkActionRequestBody", + "type": "Object", + "tags": [], + "label": "PerformKnowledgeBaseEntryBulkActionRequestBody", + "description": [], + "signature": [ + "Zod.ZodObject<{ delete: Zod.ZodOptional; ids: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { query?: string | undefined; ids?: string[] | undefined; }, { query?: string | undefined; ids?: string[] | undefined; }>>; create: Zod.ZodOptional; text: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { text: string; metadata: { source: string; required: boolean; kbResource: string; }; }, { text: string; metadata: { source: string; required: boolean; kbResource: string; }; }>, \"many\">>; update: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { id: string; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; }, { id: string; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; }>, \"many\">>; }, \"strip\", Zod.ZodTypeAny, { delete?: { query?: string | undefined; ids?: string[] | undefined; } | undefined; create?: { text: string; metadata: { source: string; required: boolean; kbResource: string; }; }[] | undefined; update?: { id: string; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; }[] | undefined; }, { delete?: { query?: string | undefined; ids?: string[] | undefined; } | undefined; create?: { text: string; metadata: { source: string; required: boolean; kbResource: string; }; }[] | undefined; update?: { id: string; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; }[] | undefined; }>" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/bulk_crud_knowledge_base_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.PerformKnowledgeBaseEntryBulkActionResponse", + "type": "Object", + "tags": [], + "label": "PerformKnowledgeBaseEntryBulkActionResponse", + "description": [], + "signature": [ + "Zod.ZodObject<{ success: Zod.ZodOptional; statusCode: Zod.ZodOptional; message: Zod.ZodOptional; knowledgeBaseEntriesCount: Zod.ZodOptional; attributes: Zod.ZodObject<{ results: Zod.ZodObject<{ updated: Zod.ZodArray; id: Zod.ZodString; createdAt: Zod.ZodString; createdBy: Zod.ZodOptional; updatedAt: Zod.ZodOptional; updatedBy: Zod.ZodOptional; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; metadata: Zod.ZodOptional>; namespace: Zod.ZodString; text: Zod.ZodString; vector: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodNumber, \"strip\">>; }, \"strip\", Zod.ZodTypeAny, { modelId: string; tokens: {} & { [k: string]: number; }; }, { modelId: string; tokens: {} & { [k: string]: number; }; }>>; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }, { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }>, \"many\">; created: Zod.ZodArray; id: Zod.ZodString; createdAt: Zod.ZodString; createdBy: Zod.ZodOptional; updatedAt: Zod.ZodOptional; updatedBy: Zod.ZodOptional; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; metadata: Zod.ZodOptional>; namespace: Zod.ZodString; text: Zod.ZodString; vector: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodNumber, \"strip\">>; }, \"strip\", Zod.ZodTypeAny, { modelId: string; tokens: {} & { [k: string]: number; }; }, { modelId: string; tokens: {} & { [k: string]: number; }; }>>; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }, { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }>, \"many\">; deleted: Zod.ZodArray; skipped: Zod.ZodArray; skip_reason: Zod.ZodLiteral<\"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\">; }, \"strip\", Zod.ZodTypeAny, { id: string; skip_reason: \"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\"; name?: string | undefined; }, { id: string; skip_reason: \"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\"; name?: string | undefined; }>, \"many\">; }, \"strip\", Zod.ZodTypeAny, { created: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; updated: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; skipped: { id: string; skip_reason: \"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }, { created: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; updated: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; skipped: { id: string; skip_reason: \"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }>; summary: Zod.ZodObject<{ failed: Zod.ZodNumber; skipped: Zod.ZodNumber; succeeded: Zod.ZodNumber; total: Zod.ZodNumber; }, \"strip\", Zod.ZodTypeAny, { total: number; succeeded: number; failed: number; skipped: number; }, { total: number; succeeded: number; failed: number; skipped: number; }>; errors: Zod.ZodOptional; knowledgeBaseEntries: Zod.ZodArray; }, \"strip\", Zod.ZodTypeAny, { id: string; name?: string | undefined; }, { id: string; name?: string | undefined; }>, \"many\">; }, \"strip\", Zod.ZodTypeAny, { message: string; statusCode: number; knowledgeBaseEntries: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }, { message: string; statusCode: number; knowledgeBaseEntries: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }>, \"many\">>; }, \"strip\", Zod.ZodTypeAny, { results: { created: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; updated: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; skipped: { id: string; skip_reason: \"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }; summary: { total: number; succeeded: number; failed: number; skipped: number; }; errors?: { message: string; statusCode: number; knowledgeBaseEntries: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }[] | undefined; }, { results: { created: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; updated: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; skipped: { id: string; skip_reason: \"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }; summary: { total: number; succeeded: number; failed: number; skipped: number; }; errors?: { message: string; statusCode: number; knowledgeBaseEntries: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }[] | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { attributes: { results: { created: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; updated: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; skipped: { id: string; skip_reason: \"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }; summary: { total: number; succeeded: number; failed: number; skipped: number; }; errors?: { message: string; statusCode: number; knowledgeBaseEntries: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }[] | undefined; }; success?: boolean | undefined; statusCode?: number | undefined; message?: string | undefined; knowledgeBaseEntriesCount?: number | undefined; }, { attributes: { results: { created: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; updated: { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }[]; skipped: { id: string; skip_reason: \"KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED\"; name?: string | undefined; }[]; deleted: string[]; }; summary: { total: number; succeeded: number; failed: number; skipped: number; }; errors?: { message: string; statusCode: number; knowledgeBaseEntries: { id: string; name?: string | undefined; }[]; err_code?: string | undefined; }[] | undefined; }; success?: boolean | undefined; statusCode?: number | undefined; message?: string | undefined; knowledgeBaseEntriesCount?: number | undefined; }>" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/bulk_crud_knowledge_base_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/elastic-assistant-common", "id": "def-common.PostEvaluateBody", @@ -3293,7 +4166,7 @@ "label": "ReadConversationResponse", "description": [], "signature": [ - "Zod.ZodObject<{ id: Zod.ZodUnion<[Zod.ZodString, Zod.ZodString]>; title: Zod.ZodString; category: Zod.ZodEnum<[\"assistant\", \"insights\"]>; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; timestamp: Zod.ZodOptional; updatedAt: Zod.ZodOptional; createdAt: Zod.ZodString; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; namespace: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }>" + "Zod.ZodObject<{ id: Zod.ZodString; title: Zod.ZodString; category: Zod.ZodEnum<[\"assistant\", \"insights\"]>; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; timestamp: Zod.ZodOptional; updatedAt: Zod.ZodOptional; createdAt: Zod.ZodString; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; namespace: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }>" ], "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/crud_conversation_route.gen.ts", "deprecated": false, @@ -3315,6 +4188,36 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.ReadKnowledgeBaseEntryRequestParams", + "type": "Object", + "tags": [], + "label": "ReadKnowledgeBaseEntryRequestParams", + "description": [], + "signature": [ + "Zod.ZodObject<{ id: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; }, { id: string; }>" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_knowledge_base_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.ReadKnowledgeBaseEntryResponse", + "type": "Object", + "tags": [], + "label": "ReadKnowledgeBaseEntryResponse", + "description": [], + "signature": [ + "Zod.ZodObject<{ timestamp: Zod.ZodOptional; id: Zod.ZodString; createdAt: Zod.ZodString; createdBy: Zod.ZodOptional; updatedAt: Zod.ZodOptional; updatedBy: Zod.ZodOptional; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; metadata: Zod.ZodOptional>; namespace: Zod.ZodString; text: Zod.ZodString; vector: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodNumber, \"strip\">>; }, \"strip\", Zod.ZodTypeAny, { modelId: string; tokens: {} & { [k: string]: number; }; }, { modelId: string; tokens: {} & { [k: string]: number; }; }>>; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }, { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }>" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_knowledge_base_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/elastic-assistant-common", "id": "def-common.ReadKnowledgeBaseRequestParams", @@ -3338,7 +4241,7 @@ "label": "ReadKnowledgeBaseResponse", "description": [], "signature": [ - "Zod.ZodObject<{ elser_exists: Zod.ZodOptional; index_exists: Zod.ZodOptional; pipeline_exists: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { elser_exists?: boolean | undefined; index_exists?: boolean | undefined; pipeline_exists?: boolean | undefined; }, { elser_exists?: boolean | undefined; index_exists?: boolean | undefined; pipeline_exists?: boolean | undefined; }>" + "Zod.ZodObject<{ elser_exists: Zod.ZodOptional; esql_exists: Zod.ZodOptional; index_exists: Zod.ZodOptional; is_setup_in_progress: Zod.ZodOptional; pipeline_exists: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { elser_exists?: boolean | undefined; esql_exists?: boolean | undefined; index_exists?: boolean | undefined; is_setup_in_progress?: boolean | undefined; pipeline_exists?: boolean | undefined; }, { elser_exists?: boolean | undefined; esql_exists?: boolean | undefined; index_exists?: boolean | undefined; is_setup_in_progress?: boolean | undefined; pipeline_exists?: boolean | undefined; }>" ], "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.gen.ts", "deprecated": false, @@ -3413,7 +4316,7 @@ "label": "UpdateConversationRequestBody", "description": [], "signature": [ - "Zod.ZodObject<{ id: Zod.ZodUnion<[Zod.ZodString, Zod.ZodString]>; title: Zod.ZodOptional; category: Zod.ZodOptional>; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; excludeFromLastConversationStorage: Zod.ZodOptional; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; }, \"strip\", Zod.ZodTypeAny, { id: string; title?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; }, { id: string; title?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; }>" + "Zod.ZodObject<{ id: Zod.ZodString; title: Zod.ZodOptional; category: Zod.ZodOptional>; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; excludeFromLastConversationStorage: Zod.ZodOptional; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; }, \"strip\", Zod.ZodTypeAny, { id: string; title?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; }, { id: string; title?: string | undefined; category?: \"assistant\" | \"insights\" | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; excludeFromLastConversationStorage?: boolean | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; }>" ], "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/crud_conversation_route.gen.ts", "deprecated": false, @@ -3443,13 +4346,58 @@ "label": "UpdateConversationResponse", "description": [], "signature": [ - "Zod.ZodObject<{ id: Zod.ZodUnion<[Zod.ZodString, Zod.ZodString]>; title: Zod.ZodString; category: Zod.ZodEnum<[\"assistant\", \"insights\"]>; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; timestamp: Zod.ZodOptional; updatedAt: Zod.ZodOptional; createdAt: Zod.ZodString; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; namespace: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }>" + "Zod.ZodObject<{ id: Zod.ZodString; title: Zod.ZodString; category: Zod.ZodEnum<[\"assistant\", \"insights\"]>; summary: Zod.ZodOptional; timestamp: Zod.ZodOptional; public: Zod.ZodOptional; confidence: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }, { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; }>>; timestamp: Zod.ZodOptional; updatedAt: Zod.ZodOptional; createdAt: Zod.ZodString; replacements: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodString, \"strip\">>>; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; messages: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; role: Zod.ZodEnum<[\"system\", \"user\", \"assistant\"]>; timestamp: Zod.ZodString; isError: Zod.ZodOptional; traceData: Zod.ZodOptional; traceId: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { transactionId?: string | undefined; traceId?: string | undefined; }, { transactionId?: string | undefined; traceId?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }, { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }>, \"many\">>; apiConfig: Zod.ZodOptional; provider: Zod.ZodOptional>; model: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }, { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; }>>; isDefault: Zod.ZodOptional; excludeFromLastConversationStorage: Zod.ZodOptional; namespace: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectOutputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }, { id: string; namespace: string; title: string; createdAt: string; category: \"assistant\" | \"insights\"; users: { id?: string | undefined; name?: string | undefined; }[]; summary?: { content?: string | undefined; timestamp?: string | undefined; public?: boolean | undefined; confidence?: \"medium\" | \"low\" | \"high\" | undefined; } | undefined; timestamp?: string | undefined; updatedAt?: string | undefined; replacements?: Zod.objectInputType<{}, Zod.ZodString, \"strip\"> | undefined; messages?: { timestamp: string; role: \"user\" | \"system\" | \"assistant\"; content: string; reader?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; isError?: boolean | undefined; traceData?: { transactionId?: string | undefined; traceId?: string | undefined; } | undefined; }[] | undefined; apiConfig?: { connectorId: string; actionTypeId: string; defaultSystemPromptId?: string | undefined; provider?: \"OpenAI\" | \"Azure OpenAI\" | undefined; model?: string | undefined; } | undefined; isDefault?: boolean | undefined; excludeFromLastConversationStorage?: boolean | undefined; }>" ], "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/crud_conversation_route.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.UpdateKnowledgeBaseEntryRequestBody", + "type": "Object", + "tags": [], + "label": "UpdateKnowledgeBaseEntryRequestBody", + "description": [], + "signature": [ + "Zod.ZodObject<{ id: Zod.ZodString; metadata: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { id: string; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; }, { id: string; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; }>" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_knowledge_base_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.UpdateKnowledgeBaseEntryRequestParams", + "type": "Object", + "tags": [], + "label": "UpdateKnowledgeBaseEntryRequestParams", + "description": [], + "signature": [ + "Zod.ZodObject<{ id: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; }, { id: string; }>" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_knowledge_base_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.UpdateKnowledgeBaseEntryResponse", + "type": "Object", + "tags": [], + "label": "UpdateKnowledgeBaseEntryResponse", + "description": [], + "signature": [ + "Zod.ZodObject<{ timestamp: Zod.ZodOptional; id: Zod.ZodString; createdAt: Zod.ZodString; createdBy: Zod.ZodOptional; updatedAt: Zod.ZodOptional; updatedBy: Zod.ZodOptional; users: Zod.ZodArray; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>, \"many\">; metadata: Zod.ZodOptional>; namespace: Zod.ZodString; text: Zod.ZodString; vector: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodNumber, \"strip\">>; }, \"strip\", Zod.ZodTypeAny, { modelId: string; tokens: {} & { [k: string]: number; }; }, { modelId: string; tokens: {} & { [k: string]: number; }; }>>; }, \"strip\", Zod.ZodTypeAny, { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }, { id: string; namespace: string; text: string; createdAt: string; users: { id?: string | undefined; name?: string | undefined; }[]; timestamp?: string | undefined; createdBy?: string | undefined; updatedAt?: string | undefined; updatedBy?: string | undefined; metadata?: { source: string; required: boolean; kbResource: string; } | undefined; vector?: { modelId: string; tokens: {} & { [k: string]: number; }; } | undefined; }>" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_knowledge_base_route.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/elastic-assistant-common", "id": "def-common.User", @@ -3460,7 +4408,7 @@ "signature": [ "Zod.ZodObject<{ id: Zod.ZodOptional; name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; name?: string | undefined; }, { id?: string | undefined; name?: string | undefined; }>" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -3475,7 +4423,22 @@ "signature": [ "Zod.ZodString" ], - "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts", + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.gen.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/elastic-assistant-common", + "id": "def-common.Vector", + "type": "Object", + "tags": [], + "label": "Vector", + "description": [], + "signature": [ + "Zod.ZodObject<{ modelId: Zod.ZodString; tokens: Zod.ZodObject<{}, \"strip\", Zod.ZodNumber, Zod.objectOutputType<{}, Zod.ZodNumber, \"strip\">, Zod.objectInputType<{}, Zod.ZodNumber, \"strip\">>; }, \"strip\", Zod.ZodTypeAny, { modelId: string; tokens: {} & { [k: string]: number; }; }, { modelId: string; tokens: {} & { [k: string]: number; }; }>" + ], + "path": "x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/common_attributes.gen.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false diff --git a/api_docs/kbn_elastic_assistant_common.mdx b/api_docs/kbn_elastic_assistant_common.mdx index 1d9c881ebc379..cf7c80748f496 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-assistant-common'] --- import kbnElasticAssistantCommonObj from './kbn_elastic_assistant_common.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/security-generative-ai](https://github.com/orgs/elastic/teams/ | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 232 | 0 | 217 | 2 | +| 295 | 0 | 276 | 0 | ## Common diff --git a/api_docs/kbn_entities_schema.mdx b/api_docs/kbn_entities_schema.mdx index 7fdc3856050d6..a4df5b3b14aa1 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-05-20 +date: 2024-05-23 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 7509c63e77921..96132fc254d3c 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-05-20 +date: 2024-05-23 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 f6680c048cf14..16ff71a822423 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-05-20 +date: 2024-05-23 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 f49662d452ced..799368f50a71f 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-errors'] --- import kbnEsErrorsObj from './kbn_es_errors.devdocs.json'; diff --git a/api_docs/kbn_es_query.devdocs.json b/api_docs/kbn_es_query.devdocs.json index c52adf2911a0c..d4e035d56caa0 100644 --- a/api_docs/kbn_es_query.devdocs.json +++ b/api_docs/kbn_es_query.devdocs.json @@ -678,8 +678,8 @@ "pluginId": "@kbn/es-query", "scope": "common", "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.DataViewBase", - "text": "DataViewBase" + "section": "def-common.DataViewBaseNoFields", + "text": "DataViewBaseNoFields" }, ") => ", { @@ -731,8 +731,8 @@ "pluginId": "@kbn/es-query", "scope": "common", "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.DataViewBase", - "text": "DataViewBase" + "section": "def-common.DataViewBaseNoFields", + "text": "DataViewBaseNoFields" } ], "path": "packages/kbn-es-query/src/filters/build_filters/exists_filter.ts", @@ -997,8 +997,8 @@ "pluginId": "@kbn/es-query", "scope": "common", "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.DataViewBase", - "text": "DataViewBase" + "section": "def-common.DataViewBaseNoFields", + "text": "DataViewBaseNoFields" }, ") => ", { @@ -1069,8 +1069,8 @@ "pluginId": "@kbn/es-query", "scope": "common", "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.DataViewBase", - "text": "DataViewBase" + "section": "def-common.DataViewBaseNoFields", + "text": "DataViewBaseNoFields" } ], "path": "packages/kbn-es-query/src/filters/build_filters/phrase_filter.ts", @@ -1109,8 +1109,8 @@ "pluginId": "@kbn/es-query", "scope": "common", "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.DataViewBase", - "text": "DataViewBase" + "section": "def-common.DataViewBaseNoFields", + "text": "DataViewBaseNoFields" }, ") => ", { @@ -1174,8 +1174,8 @@ "pluginId": "@kbn/es-query", "scope": "common", "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.DataViewBase", - "text": "DataViewBase" + "section": "def-common.DataViewBaseNoFields", + "text": "DataViewBaseNoFields" } ], "path": "packages/kbn-es-query/src/filters/build_filters/phrases_filter.ts", @@ -1448,8 +1448,8 @@ "pluginId": "@kbn/es-query", "scope": "common", "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.DataViewBase", - "text": "DataViewBase" + "section": "def-common.DataViewBaseNoFields", + "text": "DataViewBaseNoFields" }, " | undefined, formattedValue?: string | undefined) => ", { @@ -1528,8 +1528,8 @@ "pluginId": "@kbn/es-query", "scope": "common", "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.DataViewBase", - "text": "DataViewBase" + "section": "def-common.DataViewBaseNoFields", + "text": "DataViewBaseNoFields" }, " | undefined" ], @@ -2683,6 +2683,86 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/es-query", + "id": "def-common.getKqlFieldNames", + "type": "Function", + "tags": [], + "label": "getKqlFieldNames", + "description": [], + "signature": [ + "(node: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.KueryNode", + "text": "KueryNode" + }, + ") => string[]" + ], + "path": "packages/kbn-es-query/src/kuery/utils/get_kql_fields.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/es-query", + "id": "def-common.getKqlFieldNames.$1", + "type": "Object", + "tags": [], + "label": "node", + "description": [], + "signature": [ + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.KueryNode", + "text": "KueryNode" + } + ], + "path": "packages/kbn-es-query/src/kuery/utils/get_kql_fields.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/es-query", + "id": "def-common.getKqlFieldNamesFromExpression", + "type": "Function", + "tags": [], + "label": "getKqlFieldNamesFromExpression", + "description": [], + "signature": [ + "(expression: string) => string[]" + ], + "path": "packages/kbn-es-query/src/kuery/utils/get_kql_fields.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/es-query", + "id": "def-common.getKqlFieldNamesFromExpression.$1", + "type": "string", + "tags": [], + "label": "expression", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-es-query/src/kuery/utils/get_kql_fields.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/es-query", "id": "def-common.getLanguageDisplayName", @@ -5247,6 +5327,99 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/es-query", + "id": "def-common.DataViewBase", + "type": "Interface", + "tags": [], + "label": "DataViewBase", + "description": [ + "\nA base interface for an index pattern" + ], + "signature": [ + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.DataViewBase", + "text": "DataViewBase" + }, + " extends ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.DataViewBaseNoFields", + "text": "DataViewBaseNoFields" + } + ], + "path": "packages/kbn-es-query/src/es_query/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/es-query", + "id": "def-common.DataViewBase.fields", + "type": "Array", + "tags": [], + "label": "fields", + "description": [], + "signature": [ + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.DataViewFieldBase", + "text": "DataViewFieldBase" + }, + "[]" + ], + "path": "packages/kbn-es-query/src/es_query/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/es-query", + "id": "def-common.DataViewBaseNoFields", + "type": "Interface", + "tags": [], + "label": "DataViewBaseNoFields", + "description": [], + "path": "packages/kbn-es-query/src/es_query/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/es-query", + "id": "def-common.DataViewBaseNoFields.id", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-es-query/src/es_query/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/es-query", + "id": "def-common.DataViewBaseNoFields.title", + "type": "string", + "tags": [], + "label": "title", + "description": [], + "path": "packages/kbn-es-query/src/es_query/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/es-query", "id": "def-common.EsQueryFiltersConfig", @@ -5923,31 +6096,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "@kbn/es-query", - "id": "def-common.DataViewBase", - "type": "Type", - "tags": [], - "label": "DataViewBase", - "description": [ - "\nA base interface for an index pattern" - ], - "signature": [ - "{ fields: ", - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.DataViewFieldBase", - "text": "DataViewFieldBase" - }, - "[]; id?: string | undefined; title: string; }" - ], - "path": "packages/kbn-es-query/src/es_query/types.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "@kbn/es-query", "id": "def-common.DataViewFieldBase", diff --git a/api_docs/kbn_es_query.mdx b/api_docs/kbn_es_query.mdx index 1f865d800f153..44e318bf15f0c 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-query'] --- import kbnEsQueryObj from './kbn_es_query.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 | |-------------------|-----------|------------------------|-----------------| -| 261 | 1 | 201 | 15 | +| 269 | 1 | 209 | 15 | ## Common diff --git a/api_docs/kbn_es_types.mdx b/api_docs/kbn_es_types.mdx index 8a65e5353d999..b521ff0007e34 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-types'] --- import kbnEsTypesObj from './kbn_es_types.devdocs.json'; diff --git a/api_docs/kbn_eslint_plugin_imports.mdx b/api_docs/kbn_eslint_plugin_imports.mdx index f9894eb340d78..5c0c2f21d9b18 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-05-20 +date: 2024-05-23 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 c73424f7578d0..c66f5b2b45168 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/esql-ast'] --- import kbnEsqlAstObj from './kbn_esql_ast.devdocs.json'; diff --git a/api_docs/kbn_esql_utils.mdx b/api_docs/kbn_esql_utils.mdx index 3185b83461179..cad8552bbfb74 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/esql-utils'] --- import kbnEsqlUtilsObj from './kbn_esql_utils.devdocs.json'; diff --git a/api_docs/kbn_esql_validation_autocomplete.mdx b/api_docs/kbn_esql_validation_autocomplete.mdx index 6891661b0b28c..6e4d8c94857e9 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-05-20 +date: 2024-05-23 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 bee7e2673330f..18c22e12d03b0 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-05-20 +date: 2024-05-23 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 a0edca96484e4..552e74e798de0 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-05-20 +date: 2024-05-23 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 4f18c95f49ca2..766f689a7f821 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-05-20 +date: 2024-05-23 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 8b92a98dab6e5..3c957fd5b7d98 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-types'] --- import kbnFieldTypesObj from './kbn_field_types.devdocs.json'; diff --git a/api_docs/kbn_field_utils.mdx b/api_docs/kbn_field_utils.mdx index e1cb1259a8b1b..8bf20e6456791 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-utils'] --- import kbnFieldUtilsObj from './kbn_field_utils.devdocs.json'; diff --git a/api_docs/kbn_find_used_node_modules.mdx b/api_docs/kbn_find_used_node_modules.mdx index 3724a34fad00b..830146634fa42 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-05-20 +date: 2024-05-23 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 648c023f14d6f..378387b4cf765 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-05-20 +date: 2024-05-23 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 b545e7c3c5b34..7552398e8a0e8 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-05-20 +date: 2024-05-23 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 6681c12e8d111..40c6ee04c751c 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-05-20 +date: 2024-05-23 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 9ac51a310dad3..79f7c1862c25a 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-05-20 +date: 2024-05-23 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 068cf2df7e15f..42bc4604892ce 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-05-20 +date: 2024-05-23 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 62cc1c4471aa0..a1b190b88aff8 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-csv'] --- import kbnGenerateCsvObj from './kbn_generate_csv.devdocs.json'; diff --git a/api_docs/kbn_guided_onboarding.mdx b/api_docs/kbn_guided_onboarding.mdx index 4ccfe0bb2217b..b112ff6113e3d 100644 --- a/api_docs/kbn_guided_onboarding.mdx +++ b/api_docs/kbn_guided_onboarding.mdx @@ -8,14 +8,14 @@ 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/guided-onboarding'] --- import kbnGuidedOnboardingObj from './kbn_guided_onboarding.devdocs.json'; -Contact [@elastic/platform-onboarding](https://github.com/orgs/elastic/teams/platform-onboarding) for questions regarding this plugin. +Contact [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) for questions regarding this plugin. **Code health stats** diff --git a/api_docs/kbn_handlebars.mdx b/api_docs/kbn_handlebars.mdx index 434c0ea1c88f6..179ff82b2debd 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-05-20 +date: 2024-05-23 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 e4c64d5be2625..0a1c59217436b 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-05-20 +date: 2024-05-23 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 bc245facc9d6b..7b38d59358a2d 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-05-20 +date: 2024-05-23 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 f5260f6eb7e11..695913a037a68 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-05-20 +date: 2024-05-23 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 bb719406e334e..82d0835b8da42 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-05-20 +date: 2024-05-23 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 a0bfa7bf67e25..e84b13cc9fe75 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-05-20 +date: 2024-05-23 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 7c4c02c29dede..ba7c77726961f 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-05-20 +date: 2024-05-23 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 eaa27c6b9303a..6386e7988a0a3 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-05-20 +date: 2024-05-23 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 aad52fba0f782..d37b792d876c4 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-05-20 +date: 2024-05-23 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 dae37620023b2..8cfc15a246f12 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-05-20 +date: 2024-05-23 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 8252010eecb30..c8d859c4b17fe 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-05-20 +date: 2024-05-23 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 13232cc3f0076..9d43210527c6d 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-05-20 +date: 2024-05-23 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 387b707ef33bf..d12e963764750 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-05-20 +date: 2024-05-23 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 5e5cf0f6b7570..805f20e7226a4 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-05-20 +date: 2024-05-23 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 9d53dc3928e03..ad64e5d98d927 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/jest-serializers'] --- import kbnJestSerializersObj from './kbn_jest_serializers.devdocs.json'; diff --git a/api_docs/kbn_journeys.mdx b/api_docs/kbn_journeys.mdx index a88d3370f8737..57bc1b2ada981 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/journeys'] --- import kbnJourneysObj from './kbn_journeys.devdocs.json'; diff --git a/api_docs/kbn_json_ast.mdx b/api_docs/kbn_json_ast.mdx index 70a94bda1b19d..51c820117c270 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/json-ast'] --- import kbnJsonAstObj from './kbn_json_ast.devdocs.json'; diff --git a/api_docs/kbn_kibana_manifest_schema.mdx b/api_docs/kbn_kibana_manifest_schema.mdx index 73e8a08a8db27..538ea5c507a80 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-05-20 +date: 2024-05-23 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 b5e3a51ddc953..146345aaeb179 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-05-20 +date: 2024-05-23 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 d7cff9a698593..b35633f8361a6 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-05-20 +date: 2024-05-23 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 06dae205273db..e3412ae910c41 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-05-20 +date: 2024-05-23 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 fa0cc30a66279..60955d0cd462d 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-05-20 +date: 2024-05-23 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 3a2c914d8972f..426c55db42130 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-05-20 +date: 2024-05-23 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 c853f7684ffdf..c0140bf68d480 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-05-20 +date: 2024-05-23 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 bb5564aa4a8ed..be73355655996 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-05-20 +date: 2024-05-23 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 a26885eaf8dfc..1ee912fb368cb 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-05-20 +date: 2024-05-23 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 9a8776cf9eac4..457644c20a9cc 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-05-20 +date: 2024-05-23 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 20fab4480b4df..0455a7b289d97 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-05-20 +date: 2024-05-23 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 3319f91551d56..9054c7e56a6f3 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-05-20 +date: 2024-05-23 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 0103222f036d7..3520abbe96e68 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-05-20 +date: 2024-05-23 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 d095a0f3ce8a3..ccafde5bb2d7f 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-05-20 +date: 2024-05-23 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 0395cea532071..6163bce6749d4 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-05-20 +date: 2024-05-23 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 1ab0cdfdfc766..25e958e2feb4b 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-05-20 +date: 2024-05-23 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 c1568de1b76f5..9fc71c3702293 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-05-20 +date: 2024-05-23 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 108d8de81ef67..92fdd0236fb5c 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-05-20 +date: 2024-05-23 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 3f1ebe9b73274..ae669191d8621 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-05-20 +date: 2024-05-23 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 721d1e5c06122..dfd63d4710eb3 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-05-20 +date: 2024-05-23 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 f36575c2e9e0f..30285a09dfca3 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-05-20 +date: 2024-05-23 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 944c37620fca0..bd6b22107680d 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-05-20 +date: 2024-05-23 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 691f13089edfc..5c6e17d8abad9 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-05-20 +date: 2024-05-23 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 4627bcb5da05d..710ad20adec4c 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-05-20 +date: 2024-05-23 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 c534bb98129bf..a216086bd3a3c 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-05-20 +date: 2024-05-23 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 cf13409ca1bc2..a35a9b4eb00ef 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-05-20 +date: 2024-05-23 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 96ef4dce826c2..42efb40cecbdc 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-05-20 +date: 2024-05-23 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 2e815aec2dfba..b67ef20d08f19 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-05-20 +date: 2024-05-23 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 06944e51e96fe..1f978eb912e10 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-05-20 +date: 2024-05-23 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.devdocs.json b/api_docs/kbn_ml_date_picker.devdocs.json index c8a41eb5045fa..c07148653d9d9 100644 --- a/api_docs/kbn_ml_date_picker.devdocs.json +++ b/api_docs/kbn_ml_date_picker.devdocs.json @@ -174,6 +174,53 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/ml-date-picker", + "id": "def-common.getTimeFieldRange", + "type": "Function", + "tags": [], + "label": "getTimeFieldRange", + "description": [ + "\n" + ], + "signature": [ + "(options: GetTimeFieldRangeOptions) => Promise<", + { + "pluginId": "@kbn/ml-date-picker", + "scope": "common", + "docId": "kibKbnMlDatePickerPluginApi", + "section": "def-common.GetTimeFieldRangeResponse", + "text": "GetTimeFieldRangeResponse" + }, + ">" + ], + "path": "x-pack/packages/ml/date_picker/src/services/time_field_range.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ml-date-picker", + "id": "def-common.getTimeFieldRange.$1", + "type": "Object", + "tags": [], + "label": "options", + "description": [ + "- GetTimeFieldRangeOptions" + ], + "signature": [ + "GetTimeFieldRangeOptions" + ], + "path": "x-pack/packages/ml/date_picker/src/services/time_field_range.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [ + "GetTimeFieldRangeResponse" + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/ml-date-picker", "id": "def-common.getTimeFilterRange", diff --git a/api_docs/kbn_ml_date_picker.mdx b/api_docs/kbn_ml_date_picker.mdx index 54c601b060b36..ad175c837dd21 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-date-picker'] --- import kbnMlDatePickerObj from './kbn_ml_date_picker.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) for questi | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 48 | 0 | 0 | 0 | +| 50 | 0 | 0 | 0 | ## Common diff --git a/api_docs/kbn_ml_date_utils.mdx b/api_docs/kbn_ml_date_utils.mdx index 726a77c042d8e..2c811419bf905 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-05-20 +date: 2024-05-23 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 bb0a28fae804b..41f15ebb44a68 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-05-20 +date: 2024-05-23 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 8256a5b17dccc..39106b95bba14 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-05-20 +date: 2024-05-23 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 7d2b3849c30b2..2b3515b90755f 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-05-20 +date: 2024-05-23 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 6727da83c1138..b5de23802491c 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-05-20 +date: 2024-05-23 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 ab24b887d9836..5aded401a298c 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-05-20 +date: 2024-05-23 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 eec4d49078e26..19e300b77c4cd 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-05-20 +date: 2024-05-23 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 1038de63310e5..5e33befb8d9f3 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-05-20 +date: 2024-05-23 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 e1abbae79cd0a..63eab6d58c8ea 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-05-20 +date: 2024-05-23 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 e342bce4e66e6..9a005250a3f4f 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-05-20 +date: 2024-05-23 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 304cbc9d0c8a9..f11feff353925 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-05-20 +date: 2024-05-23 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 210206057ace2..2919eaf214688 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-05-20 +date: 2024-05-23 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 0387d847c8dab..792efd3b2a61f 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-05-20 +date: 2024-05-23 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 6fcda645376cf..4dd7ba1dd117e 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-05-20 +date: 2024-05-23 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 75a6555735baf..fb0e444daf016 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-05-20 +date: 2024-05-23 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 461abb8754801..e5dd5dbdfb6bd 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-05-20 +date: 2024-05-23 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 caae8ac209814..bb68f42ed0a9a 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-05-20 +date: 2024-05-23 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 14fab7aad9c26..07eaa24b7a330 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-05-20 +date: 2024-05-23 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 d1435c0524254..6dfe27c75c47a 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-05-20 +date: 2024-05-23 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 f3f7c2bf7b17a..67ce4594112fd 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-05-20 +date: 2024-05-23 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 54bda828e2d26..1be20b78ec6e7 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-05-20 +date: 2024-05-23 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 9ddf3b925a45e..8838dd3ccf4f0 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-05-20 +date: 2024-05-23 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 b0feb7bea0422..227e8f88b2ba7 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-05-20 +date: 2024-05-23 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 0acc2281d3ff6..66faf62bd7257 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-05-20 +date: 2024-05-23 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 a64760faad9d0..5549dddfc8bc0 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-05-20 +date: 2024-05-23 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 693f3c620391c..7226728a62f66 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-05-20 +date: 2024-05-23 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 0b4676e4d5f19..582af7e2e624e 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-05-20 +date: 2024-05-23 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 ffc91d2c719a9..055f79af8d66a 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-05-20 +date: 2024-05-23 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 0f64d776b1c11..2bdfdbb2ba21f 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-05-20 +date: 2024-05-23 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 d9947f1d9738e..08414babd3ee2 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-05-20 +date: 2024-05-23 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 20f1726a4795e..a6f15d2e94ac2 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-05-20 +date: 2024-05-23 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 8a3b0fe93837d..65cacf6a5b1a9 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-05-20 +date: 2024-05-23 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 1db3f00e4c792..35c3f10df6ff7 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-05-20 +date: 2024-05-23 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 bcd1f927c3017..0b21f659f8fda 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-helpers'] --- import kbnPluginHelpersObj from './kbn_plugin_helpers.devdocs.json'; diff --git a/api_docs/kbn_presentation_containers.devdocs.json b/api_docs/kbn_presentation_containers.devdocs.json index 990eb469d20d8..81831f10c3eea 100644 --- a/api_docs/kbn_presentation_containers.devdocs.json +++ b/api_docs/kbn_presentation_containers.devdocs.json @@ -143,29 +143,29 @@ }, { "parentPluginId": "@kbn/presentation-containers", - "id": "def-common.apiHasSerializableState", + "id": "def-common.apiHasRuntimeChildState", "type": "Function", "tags": [], - "label": "apiHasSerializableState", + "label": "apiHasRuntimeChildState", "description": [], "signature": [ - "(api: unknown) => api is ", + "(api: unknown) => api is ", { "pluginId": "@kbn/presentation-containers", "scope": "common", "docId": "kibKbnPresentationContainersPluginApi", - "section": "def-common.HasSerializableState", - "text": "HasSerializableState" + "section": "def-common.HasRuntimeChildState", + "text": "HasRuntimeChildState" }, - "" + "" ], - "path": "packages/presentation/presentation_containers/interfaces/serialized_state.ts", + "path": "packages/presentation/presentation_containers/interfaces/child_state.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "@kbn/presentation-containers", - "id": "def-common.apiHasSerializableState.$1", + "id": "def-common.apiHasRuntimeChildState.$1", "type": "Unknown", "tags": [], "label": "api", @@ -173,7 +173,7 @@ "signature": [ "unknown" ], - "path": "packages/presentation/presentation_containers/interfaces/serialized_state.ts", + "path": "packages/presentation/presentation_containers/interfaces/child_state.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -184,10 +184,10 @@ }, { "parentPluginId": "@kbn/presentation-containers", - "id": "def-common.apiIsPresentationContainer", + "id": "def-common.apiHasSaveNotification", "type": "Function", "tags": [], - "label": "apiIsPresentationContainer", + "label": "apiHasSaveNotification", "description": [], "signature": [ "(api: unknown) => api is ", @@ -195,17 +195,17 @@ "pluginId": "@kbn/presentation-containers", "scope": "common", "docId": "kibKbnPresentationContainersPluginApi", - "section": "def-common.PresentationContainer", - "text": "PresentationContainer" + "section": "def-common.HasSaveNotification", + "text": "HasSaveNotification" } ], - "path": "packages/presentation/presentation_containers/interfaces/presentation_container.ts", + "path": "packages/presentation/presentation_containers/interfaces/has_save_notification.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "@kbn/presentation-containers", - "id": "def-common.apiIsPresentationContainer.$1", + "id": "def-common.apiHasSaveNotification.$1", "type": "Unknown", "tags": [], "label": "api", @@ -213,7 +213,7 @@ "signature": [ "unknown" ], - "path": "packages/presentation/presentation_containers/interfaces/presentation_container.ts", + "path": "packages/presentation/presentation_containers/interfaces/has_save_notification.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -224,10 +224,10 @@ }, { "parentPluginId": "@kbn/presentation-containers", - "id": "def-common.apiPublishesLastSavedState", + "id": "def-common.apiHasSerializableState", "type": "Function", "tags": [], - "label": "apiPublishesLastSavedState", + "label": "apiHasSerializableState", "description": [], "signature": [ "(api: unknown) => api is ", @@ -235,17 +235,18 @@ "pluginId": "@kbn/presentation-containers", "scope": "common", "docId": "kibKbnPresentationContainersPluginApi", - "section": "def-common.PublishesLastSavedState", - "text": "PublishesLastSavedState" - } + "section": "def-common.HasSerializableState", + "text": "HasSerializableState" + }, + "" ], - "path": "packages/presentation/presentation_containers/interfaces/last_saved_state.ts", + "path": "packages/presentation/presentation_containers/interfaces/serialized_state.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "@kbn/presentation-containers", - "id": "def-common.apiPublishesLastSavedState.$1", + "id": "def-common.apiHasSerializableState.$1", "type": "Unknown", "tags": [], "label": "api", @@ -253,7 +254,7 @@ "signature": [ "unknown" ], - "path": "packages/presentation/presentation_containers/interfaces/last_saved_state.ts", + "path": "packages/presentation/presentation_containers/interfaces/serialized_state.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -264,36 +265,37 @@ }, { "parentPluginId": "@kbn/presentation-containers", - "id": "def-common.canTrackContentfulRender", + "id": "def-common.apiHasSerializedChildState", "type": "Function", "tags": [], - "label": "canTrackContentfulRender", + "label": "apiHasSerializedChildState", "description": [], "signature": [ - "(root: unknown) => root is ", + "(api: unknown) => api is ", { "pluginId": "@kbn/presentation-containers", "scope": "common", "docId": "kibKbnPresentationContainersPluginApi", - "section": "def-common.TrackContentfulRender", - "text": "TrackContentfulRender" - } + "section": "def-common.HasSerializedChildState", + "text": "HasSerializedChildState" + }, + "" ], - "path": "packages/presentation/presentation_containers/interfaces/track_contentful_render.ts", + "path": "packages/presentation/presentation_containers/interfaces/child_state.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "@kbn/presentation-containers", - "id": "def-common.canTrackContentfulRender.$1", + "id": "def-common.apiHasSerializedChildState.$1", "type": "Unknown", "tags": [], - "label": "root", + "label": "api", "description": [], "signature": [ "unknown" ], - "path": "packages/presentation/presentation_containers/interfaces/track_contentful_render.ts", + "path": "packages/presentation/presentation_containers/interfaces/child_state.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -304,21 +306,20 @@ }, { "parentPluginId": "@kbn/presentation-containers", - "id": "def-common.getContainerParentFromAPI", + "id": "def-common.apiIsPresentationContainer", "type": "Function", "tags": [], - "label": "getContainerParentFromAPI", + "label": "apiIsPresentationContainer", "description": [], "signature": [ - "(api: unknown) => ", + "(api: unknown) => api is ", { "pluginId": "@kbn/presentation-containers", "scope": "common", "docId": "kibKbnPresentationContainersPluginApi", "section": "def-common.PresentationContainer", "text": "PresentationContainer" - }, - " | undefined" + } ], "path": "packages/presentation/presentation_containers/interfaces/presentation_container.ts", "deprecated": false, @@ -326,7 +327,7 @@ "children": [ { "parentPluginId": "@kbn/presentation-containers", - "id": "def-common.getContainerParentFromAPI.$1", + "id": "def-common.apiIsPresentationContainer.$1", "type": "Unknown", "tags": [], "label": "api", @@ -345,83 +346,77 @@ }, { "parentPluginId": "@kbn/presentation-containers", - "id": "def-common.getLastSavedStateSubjectForChild", + "id": "def-common.canTrackContentfulRender", "type": "Function", "tags": [], - "label": "getLastSavedStateSubjectForChild", + "label": "canTrackContentfulRender", "description": [], "signature": [ - "(parentApi: unknown, childId: string, deserializer: (state: ", + "(root: unknown) => root is ", { "pluginId": "@kbn/presentation-containers", "scope": "common", "docId": "kibKbnPresentationContainersPluginApi", - "section": "def-common.SerializedPanelState", - "text": "SerializedPanelState" - }, - ") => RuntimeState) => ", - { - "pluginId": "@kbn/presentation-publishing", - "scope": "common", - "docId": "kibKbnPresentationPublishingPluginApi", - "section": "def-common.PublishingSubject", - "text": "PublishingSubject" - }, - " | undefined" + "section": "def-common.TrackContentfulRender", + "text": "TrackContentfulRender" + } ], - "path": "packages/presentation/presentation_containers/interfaces/last_saved_state.ts", + "path": "packages/presentation/presentation_containers/interfaces/track_contentful_render.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "@kbn/presentation-containers", - "id": "def-common.getLastSavedStateSubjectForChild.$1", + "id": "def-common.canTrackContentfulRender.$1", "type": "Unknown", "tags": [], - "label": "parentApi", + "label": "root", "description": [], "signature": [ "unknown" ], - "path": "packages/presentation/presentation_containers/interfaces/last_saved_state.ts", + "path": "packages/presentation/presentation_containers/interfaces/track_contentful_render.ts", "deprecated": false, "trackAdoption": false, "isRequired": true - }, + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/presentation-containers", + "id": "def-common.getContainerParentFromAPI", + "type": "Function", + "tags": [], + "label": "getContainerParentFromAPI", + "description": [], + "signature": [ + "(api: unknown) => ", { - "parentPluginId": "@kbn/presentation-containers", - "id": "def-common.getLastSavedStateSubjectForChild.$2", - "type": "string", - "tags": [], - "label": "childId", - "description": [], - "signature": [ - "string" - ], - "path": "packages/presentation/presentation_containers/interfaces/last_saved_state.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true + "pluginId": "@kbn/presentation-containers", + "scope": "common", + "docId": "kibKbnPresentationContainersPluginApi", + "section": "def-common.PresentationContainer", + "text": "PresentationContainer" }, + " | undefined" + ], + "path": "packages/presentation/presentation_containers/interfaces/presentation_container.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ { "parentPluginId": "@kbn/presentation-containers", - "id": "def-common.getLastSavedStateSubjectForChild.$3", - "type": "Function", + "id": "def-common.getContainerParentFromAPI.$1", + "type": "Unknown", "tags": [], - "label": "deserializer", + "label": "api", "description": [], "signature": [ - "(state: ", - { - "pluginId": "@kbn/presentation-containers", - "scope": "common", - "docId": "kibKbnPresentationContainersPluginApi", - "section": "def-common.SerializedPanelState", - "text": "SerializedPanelState" - }, - ") => RuntimeState" + "unknown" ], - "path": "packages/presentation/presentation_containers/interfaces/last_saved_state.ts", + "path": "packages/presentation/presentation_containers/interfaces/presentation_container.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -869,6 +864,91 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/presentation-containers", + "id": "def-common.HasRuntimeChildState", + "type": "Interface", + "tags": [], + "label": "HasRuntimeChildState", + "description": [], + "signature": [ + { + "pluginId": "@kbn/presentation-containers", + "scope": "common", + "docId": "kibKbnPresentationContainersPluginApi", + "section": "def-common.HasRuntimeChildState", + "text": "HasRuntimeChildState" + }, + "" + ], + "path": "packages/presentation/presentation_containers/interfaces/child_state.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/presentation-containers", + "id": "def-common.HasRuntimeChildState.getRuntimeStateForChild", + "type": "Function", + "tags": [], + "label": "getRuntimeStateForChild", + "description": [], + "signature": [ + "(childId: string) => Partial | undefined" + ], + "path": "packages/presentation/presentation_containers/interfaces/child_state.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/presentation-containers", + "id": "def-common.HasRuntimeChildState.getRuntimeStateForChild.$1", + "type": "string", + "tags": [], + "label": "childId", + "description": [], + "signature": [ + "string" + ], + "path": "packages/presentation/presentation_containers/interfaces/child_state.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/presentation-containers", + "id": "def-common.HasSaveNotification", + "type": "Interface", + "tags": [], + "label": "HasSaveNotification", + "description": [], + "path": "packages/presentation/presentation_containers/interfaces/has_save_notification.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/presentation-containers", + "id": "def-common.HasSaveNotification.saveNotification$", + "type": "Object", + "tags": [], + "label": "saveNotification$", + "description": [], + "signature": [ + "Subject", + "" + ], + "path": "packages/presentation/presentation_containers/interfaces/has_save_notification.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/presentation-containers", "id": "def-common.HasSerializableState", @@ -884,7 +964,7 @@ "section": "def-common.HasSerializableState", "text": "HasSerializableState" }, - "" + "" ], "path": "packages/presentation/presentation_containers/interfaces/serialized_state.ts", "deprecated": false, @@ -896,9 +976,19 @@ "type": "Function", "tags": [], "label": "serializeState", - "description": [], + "description": [ + "\nSerializes all state into a format that can be saved into\nsome external store. The opposite of `deserialize` in the {@link ReactEmbeddableFactory}" + ], "signature": [ "() => ", + { + "pluginId": "@kbn/utility-types", + "scope": "common", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-common.MaybePromise", + "text": "MaybePromise" + }, + "<", { "pluginId": "@kbn/presentation-containers", "scope": "common", @@ -906,7 +996,113 @@ "section": "def-common.SerializedPanelState", "text": "SerializedPanelState" }, - "" + ">" + ], + "path": "packages/presentation/presentation_containers/interfaces/serialized_state.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/presentation-containers", + "id": "def-common.HasSerializedChildState", + "type": "Interface", + "tags": [], + "label": "HasSerializedChildState", + "description": [], + "signature": [ + { + "pluginId": "@kbn/presentation-containers", + "scope": "common", + "docId": "kibKbnPresentationContainersPluginApi", + "section": "def-common.HasSerializedChildState", + "text": "HasSerializedChildState" + }, + "" + ], + "path": "packages/presentation/presentation_containers/interfaces/child_state.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/presentation-containers", + "id": "def-common.HasSerializedChildState.getSerializedStateForChild", + "type": "Function", + "tags": [], + "label": "getSerializedStateForChild", + "description": [], + "signature": [ + "(childId: string) => ", + { + "pluginId": "@kbn/presentation-containers", + "scope": "common", + "docId": "kibKbnPresentationContainersPluginApi", + "section": "def-common.SerializedPanelState", + "text": "SerializedPanelState" + }, + "" + ], + "path": "packages/presentation/presentation_containers/interfaces/child_state.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/presentation-containers", + "id": "def-common.HasSerializedChildState.getSerializedStateForChild.$1", + "type": "string", + "tags": [], + "label": "childId", + "description": [], + "signature": [ + "string" + ], + "path": "packages/presentation/presentation_containers/interfaces/child_state.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/presentation-containers", + "id": "def-common.HasSnapshottableState", + "type": "Interface", + "tags": [], + "label": "HasSnapshottableState", + "description": [], + "signature": [ + { + "pluginId": "@kbn/presentation-containers", + "scope": "common", + "docId": "kibKbnPresentationContainersPluginApi", + "section": "def-common.HasSnapshottableState", + "text": "HasSnapshottableState" + }, + "" + ], + "path": "packages/presentation/presentation_containers/interfaces/serialized_state.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/presentation-containers", + "id": "def-common.HasSnapshottableState.snapshotRuntimeState", + "type": "Function", + "tags": [], + "label": "snapshotRuntimeState", + "description": [ + "\nSerializes all runtime state exactly as it appears. This could be used\nto rehydrate a component's state without needing to deserialize it." + ], + "signature": [ + "() => RuntimeState" ], "path": "packages/presentation/presentation_containers/interfaces/serialized_state.ts", "deprecated": false, @@ -1281,75 +1477,6 @@ ], "initialIsOpen": false }, - { - "parentPluginId": "@kbn/presentation-containers", - "id": "def-common.PublishesLastSavedState", - "type": "Interface", - "tags": [], - "label": "PublishesLastSavedState", - "description": [], - "path": "packages/presentation/presentation_containers/interfaces/last_saved_state.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/presentation-containers", - "id": "def-common.PublishesLastSavedState.lastSavedState", - "type": "Object", - "tags": [], - "label": "lastSavedState", - "description": [], - "signature": [ - "Subject", - "" - ], - "path": "packages/presentation/presentation_containers/interfaces/last_saved_state.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/presentation-containers", - "id": "def-common.PublishesLastSavedState.getLastSavedStateForChild", - "type": "Function", - "tags": [], - "label": "getLastSavedStateForChild", - "description": [], - "signature": [ - "(childId: string) => ", - { - "pluginId": "@kbn/presentation-containers", - "scope": "common", - "docId": "kibKbnPresentationContainersPluginApi", - "section": "def-common.SerializedPanelState", - "text": "SerializedPanelState" - }, - " | undefined" - ], - "path": "packages/presentation/presentation_containers/interfaces/last_saved_state.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/presentation-containers", - "id": "def-common.PublishesLastSavedState.getLastSavedStateForChild.$1", - "type": "string", - "tags": [], - "label": "childId", - "description": [], - "signature": [ - "string" - ], - "path": "packages/presentation/presentation_containers/interfaces/last_saved_state.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] - } - ], - "initialIsOpen": false - }, { "parentPluginId": "@kbn/presentation-containers", "id": "def-common.SerializedPanelState", diff --git a/api_docs/kbn_presentation_containers.mdx b/api_docs/kbn_presentation_containers.mdx index 82745e9533998..ab071f43423a7 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/presentation-containers'] --- import kbnPresentationContainersObj from './kbn_presentation_containers.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kib | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 64 | 0 | 60 | 1 | +| 70 | 0 | 64 | 1 | ## Common diff --git a/api_docs/kbn_presentation_publishing.devdocs.json b/api_docs/kbn_presentation_publishing.devdocs.json index 0c7f31ad4b1f9..fdfac45fbefb3 100644 --- a/api_docs/kbn_presentation_publishing.devdocs.json +++ b/api_docs/kbn_presentation_publishing.devdocs.json @@ -181,6 +181,46 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/presentation-publishing", + "id": "def-common.apiHasInPlaceLibraryTransforms", + "type": "Function", + "tags": [], + "label": "apiHasInPlaceLibraryTransforms", + "description": [], + "signature": [ + "(unknownApi: unknown) => unknownApi is ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "common", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-common.HasInPlaceLibraryTransforms", + "text": "HasInPlaceLibraryTransforms" + } + ], + "path": "packages/presentation/presentation_publishing/interfaces/has_library_transforms.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/presentation-publishing", + "id": "def-common.apiHasInPlaceLibraryTransforms.$1", + "type": "Unknown", + "tags": [], + "label": "unknownApi", + "description": [], + "signature": [ + "unknown" + ], + "path": "packages/presentation/presentation_publishing/interfaces/has_library_transforms.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/presentation-publishing", "id": "def-common.apiHasLegacyLibraryTransforms", @@ -1189,6 +1229,39 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/presentation-publishing", + "id": "def-common.areTriggersDisabled", + "type": "Function", + "tags": [], + "label": "areTriggersDisabled", + "description": [], + "signature": [ + "(api: unknown) => boolean" + ], + "path": "packages/presentation/presentation_publishing/interfaces/has_disable_triggers.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/presentation-publishing", + "id": "def-common.areTriggersDisabled.$1", + "type": "Unknown", + "tags": [], + "label": "api", + "description": [], + "signature": [ + "unknown" + ], + "path": "packages/presentation/presentation_publishing/interfaces/has_disable_triggers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/presentation-publishing", "id": "def-common.fetch$", @@ -2015,6 +2088,180 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/presentation-publishing", + "id": "def-common.useSearchApi", + "type": "Function", + "tags": [], + "label": "useSearchApi", + "description": [ + "\nReact hook that converts search props into search observable API" + ], + "signature": [ + "({\n filters,\n query,\n timeRange,\n}: { filters?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[] | undefined; query?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + " | undefined; timeRange?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined; }) => { filters$: ", + "BehaviorSubject", + "<", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[] | undefined>; query$: ", + "BehaviorSubject", + "<", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + " | undefined>; timeRange$: ", + "BehaviorSubject", + "<", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined>; }" + ], + "path": "packages/presentation/presentation_publishing/interfaces/fetch/publishes_unified_search.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/presentation-publishing", + "id": "def-common.useSearchApi.$1", + "type": "Object", + "tags": [], + "label": "{\n filters,\n query,\n timeRange,\n}", + "description": [], + "path": "packages/presentation/presentation_publishing/interfaces/fetch/publishes_unified_search.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/presentation-publishing", + "id": "def-common.useSearchApi.$1.filters", + "type": "Array", + "tags": [], + "label": "filters", + "description": [], + "signature": [ + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[] | undefined" + ], + "path": "packages/presentation/presentation_publishing/interfaces/fetch/publishes_unified_search.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/presentation-publishing", + "id": "def-common.useSearchApi.$1.query", + "type": "CompoundType", + "tags": [], + "label": "query", + "description": [], + "signature": [ + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + " | undefined" + ], + "path": "packages/presentation/presentation_publishing/interfaces/fetch/publishes_unified_search.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/presentation-publishing", + "id": "def-common.useSearchApi.$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/presentation/presentation_publishing/interfaces/fetch/publishes_unified_search.ts", + "deprecated": false, + "trackAdoption": false + } + ] + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/presentation-publishing", "id": "def-common.useStateFromPublishingSubject", @@ -2450,20 +2697,22 @@ }, { "parentPluginId": "@kbn/presentation-publishing", - "id": "def-common.HasLibraryTransforms", + "id": "def-common.HasInPlaceLibraryTransforms", "type": "Interface", "tags": [], - "label": "HasLibraryTransforms", - "description": [], + "label": "HasInPlaceLibraryTransforms", + "description": [ + "\nAPIs that inherit this interface can be linked to and unlinked from the library in place without\nre-initialization." + ], "signature": [ { "pluginId": "@kbn/presentation-publishing", "scope": "common", "docId": "kibKbnPresentationPublishingPluginApi", - "section": "def-common.HasLibraryTransforms", - "text": "HasLibraryTransforms" + "section": "def-common.HasInPlaceLibraryTransforms", + "text": "HasInPlaceLibraryTransforms" }, - "" + " extends Partial,DuplicateTitleCheck" ], "path": "packages/presentation/presentation_publishing/interfaces/has_library_transforms.ts", "deprecated": false, @@ -2471,27 +2720,173 @@ "children": [ { "parentPluginId": "@kbn/presentation-publishing", - "id": "def-common.HasLibraryTransforms.canLinkToLibrary", - "type": "Function", + "id": "def-common.HasInPlaceLibraryTransforms.libraryId$", + "type": "Object", "tags": [], - "label": "canLinkToLibrary", + "label": "libraryId$", "description": [ - "\n" + "\nThe id of the library item that this embeddable is linked to." ], "signature": [ - "() => Promise" + "{ source: ", + "Observable", + " | undefined; readonly value: string | undefined; error: (err: any) => void; forEach: { (next: (value: string | undefined) => void): Promise; (next: (value: string | undefined) => void, promiseCtor: PromiseConstructorLike): Promise; }; complete: () => void; getValue: () => string | undefined; pipe: { (): ", + "Observable", + "; (op1: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + ", op4: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + ", op4: ", + "OperatorFunction", + ", op5: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + ", op4: ", + "OperatorFunction", + ", op5: ", + "OperatorFunction", + ", op6: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + ", op4: ", + "OperatorFunction", + ", op5: ", + "OperatorFunction", + ", op6: ", + "OperatorFunction", + ", op7: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + ", op4: ", + "OperatorFunction", + ", op5: ", + "OperatorFunction", + ", op6: ", + "OperatorFunction", + ", op7: ", + "OperatorFunction", + ", op8: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + ", op4: ", + "OperatorFunction", + ", op5: ", + "OperatorFunction", + ", op6: ", + "OperatorFunction", + ", op7: ", + "OperatorFunction", + ", op8: ", + "OperatorFunction", + ", op9: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + ", op4: ", + "OperatorFunction", + ", op5: ", + "OperatorFunction", + ", op6: ", + "OperatorFunction", + ", op7: ", + "OperatorFunction", + ", op8: ", + "OperatorFunction", + ", op9: ", + "OperatorFunction", + ", ...operations: ", + "OperatorFunction", + "[]): ", + "Observable", + "; }; closed: boolean; observers: ", + "Observer", + "[]; isStopped: boolean; hasError: boolean; thrownError: any; lift: (operator: ", + "Operator", + ") => ", + "Observable", + "; unsubscribe: () => void; readonly observed: boolean; asObservable: () => ", + "Observable", + "; operator: ", + "Operator", + " | undefined; subscribe: { (observerOrNext?: Partial<", + "Observer", + "> | ((value: string | undefined) => void) | undefined): ", + "Subscription", + "; (next?: ((value: string | undefined) => void) | null | undefined, error?: ((error: any) => void) | null | undefined, complete?: (() => void) | null | undefined): ", + "Subscription", + "; }; toPromise: { (): Promise; (PromiseCtor: PromiseConstructor): Promise; (PromiseCtor: PromiseConstructorLike): Promise; }; }" ], "path": "packages/presentation/presentation_publishing/interfaces/has_library_transforms.ts", "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [ - "True when embeddable is by-value and can be converted to by-reference" - ] + "trackAdoption": false }, { "parentPluginId": "@kbn/presentation-publishing", - "id": "def-common.HasLibraryTransforms.saveToLibrary", + "id": "def-common.HasInPlaceLibraryTransforms.saveToLibrary", "type": "Function", "tags": [], "label": "saveToLibrary", @@ -2507,7 +2902,7 @@ "children": [ { "parentPluginId": "@kbn/presentation-publishing", - "id": "def-common.HasLibraryTransforms.saveToLibrary.$1", + "id": "def-common.HasInPlaceLibraryTransforms.saveToLibrary.$1", "type": "string", "tags": [], "label": "title", @@ -2527,15 +2922,59 @@ }, { "parentPluginId": "@kbn/presentation-publishing", - "id": "def-common.HasLibraryTransforms.getByReferenceState", + "id": "def-common.HasInPlaceLibraryTransforms.unlinkFromLibrary", "type": "Function", "tags": [], - "label": "getByReferenceState", + "label": "unlinkFromLibrary", "description": [ - "\n" + "\nUn-links this embeddable from the library. This method is optional, and only needed if the Embeddable\nis not meant to be re-initialized as part of the unlink operation. If the embeddable needs to be re-initialized\nafter unlinking, the getByValueState method should be used instead." ], "signature": [ - "(libraryId: string) => StateT" + "() => void" + ], + "path": "packages/presentation/presentation_publishing/interfaces/has_library_transforms.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/presentation-publishing", + "id": "def-common.HasLibraryTransforms", + "type": "Interface", + "tags": [], + "label": "HasLibraryTransforms", + "description": [ + "\nAPIs that inherit this interface can be linked to and unlinked from the library. After the save or unlink\noperation, the embeddable will be reinitialized." + ], + "signature": [ + { + "pluginId": "@kbn/presentation-publishing", + "scope": "common", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-common.HasLibraryTransforms", + "text": "HasLibraryTransforms" + }, + " extends LibraryTransformGuards,DuplicateTitleCheck" + ], + "path": "packages/presentation/presentation_publishing/interfaces/has_library_transforms.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/presentation-publishing", + "id": "def-common.HasLibraryTransforms.saveToLibrary", + "type": "Function", + "tags": [], + "label": "saveToLibrary", + "description": [ + "\nSave embeddable to library\n" + ], + "signature": [ + "(title: string) => Promise" ], "path": "packages/presentation/presentation_publishing/interfaces/has_library_transforms.ts", "deprecated": false, @@ -2543,10 +2982,10 @@ "children": [ { "parentPluginId": "@kbn/presentation-publishing", - "id": "def-common.HasLibraryTransforms.getByReferenceState.$1", + "id": "def-common.HasLibraryTransforms.saveToLibrary.$1", "type": "string", "tags": [], - "label": "libraryId", + "label": "title", "description": [], "signature": [ "string" @@ -2558,18 +2997,20 @@ } ], "returnComment": [ - "by-reference embeddable state replacing by-value embeddable state" + "id of persisted library item" ] }, { "parentPluginId": "@kbn/presentation-publishing", - "id": "def-common.HasLibraryTransforms.checkForDuplicateTitle", + "id": "def-common.HasLibraryTransforms.getByReferenceState", "type": "Function", "tags": [], - "label": "checkForDuplicateTitle", - "description": [], + "label": "getByReferenceState", + "description": [ + "\n" + ], "signature": [ - "(newTitle: string, isTitleDuplicateConfirmed: boolean, onTitleDuplicate: () => void) => Promise" + "(libraryId: string) => StateT" ], "path": "packages/presentation/presentation_publishing/interfaces/has_library_transforms.ts", "deprecated": false, @@ -2577,10 +3018,10 @@ "children": [ { "parentPluginId": "@kbn/presentation-publishing", - "id": "def-common.HasLibraryTransforms.checkForDuplicateTitle.$1", + "id": "def-common.HasLibraryTransforms.getByReferenceState.$1", "type": "string", "tags": [], - "label": "newTitle", + "label": "libraryId", "description": [], "signature": [ "string" @@ -2589,58 +3030,10 @@ "deprecated": false, "trackAdoption": false, "isRequired": true - }, - { - "parentPluginId": "@kbn/presentation-publishing", - "id": "def-common.HasLibraryTransforms.checkForDuplicateTitle.$2", - "type": "boolean", - "tags": [], - "label": "isTitleDuplicateConfirmed", - "description": [], - "signature": [ - "boolean" - ], - "path": "packages/presentation/presentation_publishing/interfaces/has_library_transforms.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "@kbn/presentation-publishing", - "id": "def-common.HasLibraryTransforms.checkForDuplicateTitle.$3", - "type": "Function", - "tags": [], - "label": "onTitleDuplicate", - "description": [], - "signature": [ - "() => void" - ], - "path": "packages/presentation/presentation_publishing/interfaces/has_library_transforms.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true } ], - "returnComment": [] - }, - { - "parentPluginId": "@kbn/presentation-publishing", - "id": "def-common.HasLibraryTransforms.canUnlinkFromLibrary", - "type": "Function", - "tags": [], - "label": "canUnlinkFromLibrary", - "description": [ - "\n" - ], - "signature": [ - "() => Promise" - ], - "path": "packages/presentation/presentation_publishing/interfaces/has_library_transforms.ts", - "deprecated": false, - "trackAdoption": false, - "children": [], "returnComment": [ - "True when embeddable is by-reference and can be converted to by-value" + "by-reference embeddable state replacing by-value embeddable state. After\nthe save operation, the embeddable will be reinitialized with the results of this method." ] }, { @@ -2660,7 +3053,7 @@ "trackAdoption": false, "children": [], "returnComment": [ - "by-value embeddable state replacing by-reference embeddable state" + "by-value embeddable state replacing by-reference embeddable state. After\nthe unlink operation, the embeddable will be reinitialized with the results of this method." ] } ], diff --git a/api_docs/kbn_presentation_publishing.mdx b/api_docs/kbn_presentation_publishing.mdx index 1d69b3c6d2a67..2fc67917af5cc 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/presentation-publishing'] --- import kbnPresentationPublishingObj from './kbn_presentation_publishing.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kib | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 194 | 0 | 163 | 5 | +| 202 | 0 | 167 | 5 | ## Common diff --git a/api_docs/kbn_profiling_utils.mdx b/api_docs/kbn_profiling_utils.mdx index 275f30a38fd66..9fc2f8b5864bc 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-05-20 +date: 2024-05-23 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 fe29e85ae2aa9..9c2a3a5a5cd2a 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-05-20 +date: 2024-05-23 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 e356efd368801..f3bdb2d182605 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-05-20 +date: 2024-05-23 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 99a1838392850..9323366fb8e0c 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-05-20 +date: 2024-05-23 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 4188949e59a4b..31b5ef2dab6f9 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-05-20 +date: 2024-05-23 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 4a873f05cace4..9a0d6bdc13094 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-05-20 +date: 2024-05-23 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 d06e602a384c7..18be98a05a8df 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-05-20 +date: 2024-05-23 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 9d153e136ade3..71ed04520f61c 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-05-20 +date: 2024-05-23 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 b68c77b1d2427..981dea6713492 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-05-20 +date: 2024-05-23 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 9afddbcc77bf0..43cd51aa7132f 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-mount'] --- import kbnReactKibanaMountObj from './kbn_react_kibana_mount.devdocs.json'; diff --git a/api_docs/kbn_repo_file_maps.mdx b/api_docs/kbn_repo_file_maps.mdx index 35f66c28ca036..fe09aeed8f7e9 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-05-20 +date: 2024-05-23 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 a2315e36827eb..bad9d35e8d070 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-05-20 +date: 2024-05-23 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 60709c8d76175..70003beedddbf 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-05-20 +date: 2024-05-23 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 46edbf94b0306..8c8b89c9b3bfe 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-05-20 +date: 2024-05-23 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 6110843c5551b..2cff15f383993 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-05-20 +date: 2024-05-23 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 3e20af5537dbd..05d469328a860 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-05-20 +date: 2024-05-23 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 6758cba46782a..3ec3ad68b59ce 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-05-20 +date: 2024-05-23 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 cbae61c8704be..05273a4956ac4 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-05-20 +date: 2024-05-23 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 e8bf737e0cf4d..e90a9d66aa7cb 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-05-20 +date: 2024-05-23 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 6fcc103f5a36d..0097258a37725 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-05-20 +date: 2024-05-23 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 0c83de45b0f78..f7bc308fcb4be 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-05-20 +date: 2024-05-23 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 e0306685b7dd7..de1b4ebdd0358 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-05-20 +date: 2024-05-23 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 31fc719ea844e..40718843e9823 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-05-20 +date: 2024-05-23 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 db9e3868a9098..917a4e32b5e4b 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-public'] --- import kbnReportingPublicObj from './kbn_reporting_public.devdocs.json'; diff --git a/api_docs/kbn_reporting_server.devdocs.json b/api_docs/kbn_reporting_server.devdocs.json index 669e6b1b6fbb3..1a84ea86e3e2a 100644 --- a/api_docs/kbn_reporting_server.devdocs.json +++ b/api_docs/kbn_reporting_server.devdocs.json @@ -1565,13 +1565,73 @@ }, { "parentPluginId": "@kbn/reporting-server", - "id": "def-server.REPORTING_SYSTEM_INDEX", + "id": "def-server.REPORTING_DATA_STREAM_ALIAS", "type": "string", "tags": [], - "label": "REPORTING_SYSTEM_INDEX", + "label": "REPORTING_DATA_STREAM_ALIAS", "description": [], "signature": [ - "\".reporting\"" + "\".kibana-reporting\"" + ], + "path": "packages/kbn-reporting/server/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/reporting-server", + "id": "def-server.REPORTING_DATA_STREAM_COMPONENT_TEMPLATE", + "type": "string", + "tags": [], + "label": "REPORTING_DATA_STREAM_COMPONENT_TEMPLATE", + "description": [], + "signature": [ + "\"kibana-reporting@custom\"" + ], + "path": "packages/kbn-reporting/server/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/reporting-server", + "id": "def-server.REPORTING_DATA_STREAM_WILDCARD", + "type": "string", + "tags": [], + "label": "REPORTING_DATA_STREAM_WILDCARD", + "description": [], + "signature": [ + "\".kibana-reporting*\"" + ], + "path": "packages/kbn-reporting/server/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/reporting-server", + "id": "def-server.REPORTING_DATA_STREAM_WILDCARD_WITH_LEGACY", + "type": "string", + "tags": [], + "label": "REPORTING_DATA_STREAM_WILDCARD_WITH_LEGACY", + "description": [], + "signature": [ + "\".reporting-*,.kibana-reporting*\"" + ], + "path": "packages/kbn-reporting/server/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/reporting-server", + "id": "def-server.REPORTING_LEGACY_INDICES", + "type": "string", + "tags": [], + "label": "REPORTING_LEGACY_INDICES", + "description": [], + "signature": [ + "\".reporting-*\"" ], "path": "packages/kbn-reporting/server/constants.ts", "deprecated": false, diff --git a/api_docs/kbn_reporting_server.mdx b/api_docs/kbn_reporting_server.mdx index 057e3b4216576..fe5657569bca3 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-server'] --- import kbnReportingServerObj from './kbn_reporting_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 | |-------------------|-----------|------------------------|-----------------| -| 88 | 0 | 87 | 0 | +| 92 | 0 | 91 | 0 | ## Server diff --git a/api_docs/kbn_resizable_layout.mdx b/api_docs/kbn_resizable_layout.mdx index 75ff9919b5216..e5400069ba68e 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/resizable-layout'] --- import kbnResizableLayoutObj from './kbn_resizable_layout.devdocs.json'; diff --git a/api_docs/kbn_rison.mdx b/api_docs/kbn_rison.mdx index 7593302c72d33..4907c4a37ef3e 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rison'] --- import kbnRisonObj from './kbn_rison.devdocs.json'; diff --git a/api_docs/kbn_router_to_openapispec.mdx b/api_docs/kbn_router_to_openapispec.mdx index a148497154005..48e2a2ee1776a 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-05-20 +date: 2024-05-23 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 00624f80bdc87..41a4910ac52be 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-05-20 +date: 2024-05-23 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 434774814e5e1..691e72088ab80 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-05-20 +date: 2024-05-23 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 660759341c092..102f7f0329abf 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-05-20 +date: 2024-05-23 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 885459bb55477..de331b656bc5f 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-05-20 +date: 2024-05-23 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.mdx b/api_docs/kbn_search_api_panels.mdx index d83b26f6fc708..1850206390776 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-05-20 +date: 2024-05-23 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 703be6afbdcd4..f7e4549263202 100644 --- a/api_docs/kbn_search_connectors.devdocs.json +++ b/api_docs/kbn_search_connectors.devdocs.json @@ -2125,7 +2125,7 @@ "section": "def-common.ElasticsearchClient", "text": "ElasticsearchClient" }, - ", connectorId: string, indexName: string) => Promise<", + ", connectorId: string, indexName: string | null) => Promise<", "Result", ">" ], @@ -2172,17 +2172,17 @@ { "parentPluginId": "@kbn/search-connectors", "id": "def-common.updateConnectorIndexName.$3", - "type": "string", + "type": "CompoundType", "tags": [], "label": "indexName", "description": [], "signature": [ - "string" + "string | null" ], "path": "packages/kbn-search-connectors/lib/update_connector_index_name.ts", "deprecated": false, "trackAdoption": false, - "isRequired": true + "isRequired": false } ], "returnComment": [], diff --git a/api_docs/kbn_search_connectors.mdx b/api_docs/kbn_search_connectors.mdx index 1eda416fa3a51..3070943a060b5 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-connectors'] --- import kbnSearchConnectorsObj from './kbn_search_connectors.devdocs.json'; diff --git a/api_docs/kbn_search_errors.mdx b/api_docs/kbn_search_errors.mdx index cf687aaae3b14..9c8417589547e 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-05-20 +date: 2024-05-23 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 343eb75e8bcc3..e8b8238c40c5e 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-05-20 +date: 2024-05-23 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 8166b5a31026a..a8a3a4ad81ad2 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-05-20 +date: 2024-05-23 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 88ba7c3a0a52c..7feb038298c02 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-types'] --- import kbnSearchTypesObj from './kbn_search_types.devdocs.json'; diff --git a/api_docs/kbn_security_hardening.mdx b/api_docs/kbn_security_hardening.mdx index 519bec9afc817..48d46cce5967f 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-05-20 +date: 2024-05-23 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 bf526f1d45a54..d5de66f31e882 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-05-20 +date: 2024-05-23 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 f32b2f136dab7..cbdb02146f854 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-plugin-types-public'] --- import kbnSecurityPluginTypesPublicObj from './kbn_security_plugin_types_public.devdocs.json'; diff --git a/api_docs/kbn_security_plugin_types_server.devdocs.json b/api_docs/kbn_security_plugin_types_server.devdocs.json index f01c8ccff6b47..834476b9400b5 100644 --- a/api_docs/kbn_security_plugin_types_server.devdocs.json +++ b/api_docs/kbn_security_plugin_types_server.devdocs.json @@ -3832,7 +3832,7 @@ "label": "CreateAPIKeyParams", "description": [], "signature": [ - "Readonly<{ type?: \"rest\" | undefined; metadata?: Readonly<{} & {}> | undefined; expiration?: string | undefined; } & { name: string; role_descriptors: Record>; }> | Readonly<{ type?: \"rest\" | undefined; metadata?: Readonly<{} & {}> | undefined; expiration?: string | undefined; } & { name: string; kibana_role_descriptors: Record | undefined; } & { spaces: string[] | \"*\"[]; }>[]; elasticsearch: Readonly<{ cluster?: string[] | undefined; indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; }>[] | undefined; remote_cluster?: Readonly<{} & { privileges: string[]; clusters: string[]; }>[] | undefined; remote_indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; clusters: string[]; }>[] | undefined; run_as?: string[] | undefined; } & {}>; }>>; }> | Readonly<{ metadata?: Readonly<{} & {}> | undefined; expiration?: string | undefined; } & { type: \"cross_cluster\"; name: string; access: Readonly<{ search?: Readonly<{} & { names: string[]; }>[] | undefined; replication?: Readonly<{} & { names: string[]; }>[] | undefined; } & {}>; }>" + "Readonly<{ type?: \"rest\" | undefined; metadata?: Readonly<{} & {}> | undefined; expiration?: string | undefined; } & { name: string; role_descriptors: Record>; }> | Readonly<{ type?: \"rest\" | undefined; metadata?: Readonly<{} & {}> | undefined; expiration?: string | undefined; } & { name: string; kibana_role_descriptors: Record | undefined; } & { spaces: string[] | \"*\"[]; }>[]; elasticsearch: Readonly<{ cluster?: string[] | undefined; indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; }>[] | undefined; remote_cluster?: Readonly<{} & { privileges: string[]; clusters: string[]; }>[] | undefined; remote_indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; clusters: string[]; }>[] | undefined; run_as?: string[] | undefined; } & {}>; }>>; }> | Readonly<{ metadata?: Readonly<{} & {}> | undefined; expiration?: string | undefined; } & { type: \"cross_cluster\"; name: string; access: Readonly<{ search?: Readonly<{ query?: any; field_security?: any; allow_restricted_indices?: boolean | undefined; } & { names: string[]; }>[] | undefined; replication?: Readonly<{} & { names: string[]; }>[] | undefined; } & {}>; }>" ], "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", "deprecated": false, @@ -3864,7 +3864,7 @@ "label": "CreateCrossClusterAPIKeyParams", "description": [], "signature": [ - "{ readonly metadata?: Readonly<{} & {}> | undefined; readonly expiration?: string | undefined; readonly type: \"cross_cluster\"; readonly name: string; readonly access: Readonly<{ search?: Readonly<{} & { names: string[]; }>[] | undefined; replication?: Readonly<{} & { names: string[]; }>[] | undefined; } & {}>; }" + "{ readonly metadata?: Readonly<{} & {}> | undefined; readonly expiration?: string | undefined; readonly type: \"cross_cluster\"; readonly name: string; readonly access: Readonly<{ search?: Readonly<{ query?: any; field_security?: any; allow_restricted_indices?: boolean | undefined; } & { names: string[]; }>[] | undefined; replication?: Readonly<{} & { names: string[]; }>[] | undefined; } & {}>; }" ], "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", "deprecated": false, @@ -4050,7 +4050,7 @@ "section": "def-common.Type", "text": "Type" }, - "[] | undefined>; replication: ", + "[] | undefined>; replication: ", { "pluginId": "@kbn/config-schema", "scope": "common", diff --git a/api_docs/kbn_security_plugin_types_server.mdx b/api_docs/kbn_security_plugin_types_server.mdx index 068253b884d66..e146956f146dc 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-05-20 +date: 2024-05-23 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 7e68576b0b1d9..7d1e04d34e424 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-05-20 +date: 2024-05-23 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 d706a7302fe4b..865b8e7619fbe 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-05-20 +date: 2024-05-23 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 a72a4ccc8522c..bf310423eb6ab 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-05-20 +date: 2024-05-23 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 7b2b9cd6e792f..cdb29e59ee57f 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-05-20 +date: 2024-05-23 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 ed2d948903f0c..683a5c6be4465 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-autocomplete'] --- import kbnSecuritysolutionAutocompleteObj from './kbn_securitysolution_autocomplete.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_data_table.mdx b/api_docs/kbn_securitysolution_data_table.mdx index 562c5faaf5a03..ed0e0af911d1e 100644 --- a/api_docs/kbn_securitysolution_data_table.mdx +++ b/api_docs/kbn_securitysolution_data_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-data-table title: "@kbn/securitysolution-data-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-data-table plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-data-table'] --- import kbnSecuritysolutionDataTableObj from './kbn_securitysolution_data_table.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_ecs.mdx b/api_docs/kbn_securitysolution_ecs.mdx index c550f218f43e8..9f7b308d5b293 100644 --- a/api_docs/kbn_securitysolution_ecs.mdx +++ b/api_docs/kbn_securitysolution_ecs.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-ecs title: "@kbn/securitysolution-ecs" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-ecs plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-ecs'] --- import kbnSecuritysolutionEcsObj from './kbn_securitysolution_ecs.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_es_utils.mdx b/api_docs/kbn_securitysolution_es_utils.mdx index 75db667e949f4..ce73e54737277 100644 --- a/api_docs/kbn_securitysolution_es_utils.mdx +++ b/api_docs/kbn_securitysolution_es_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-es-utils title: "@kbn/securitysolution-es-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-es-utils plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-es-utils'] --- import kbnSecuritysolutionEsUtilsObj from './kbn_securitysolution_es_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_exception_list_components.mdx b/api_docs/kbn_securitysolution_exception_list_components.mdx index e9a6389ff2b3f..d9747ffe16525 100644 --- a/api_docs/kbn_securitysolution_exception_list_components.mdx +++ b/api_docs/kbn_securitysolution_exception_list_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-exception-list-components title: "@kbn/securitysolution-exception-list-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-exception-list-components plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-exception-list-components'] --- import kbnSecuritysolutionExceptionListComponentsObj from './kbn_securitysolution_exception_list_components.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_grouping.mdx b/api_docs/kbn_securitysolution_grouping.mdx index d8e4fcbf3ddde..62c8db1c65d20 100644 --- a/api_docs/kbn_securitysolution_grouping.mdx +++ b/api_docs/kbn_securitysolution_grouping.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-grouping title: "@kbn/securitysolution-grouping" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-grouping plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-grouping'] --- import kbnSecuritysolutionGroupingObj from './kbn_securitysolution_grouping.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_hook_utils.mdx b/api_docs/kbn_securitysolution_hook_utils.mdx index ab9bc1108f5d2..4cb3bbc1434fa 100644 --- a/api_docs/kbn_securitysolution_hook_utils.mdx +++ b/api_docs/kbn_securitysolution_hook_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-hook-utils title: "@kbn/securitysolution-hook-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-hook-utils plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-hook-utils'] --- import kbnSecuritysolutionHookUtilsObj from './kbn_securitysolution_hook_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx index 1b3a7c22fecd5..5f5a373b7ee0c 100644 --- a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-alerting-types title: "@kbn/securitysolution-io-ts-alerting-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-alerting-types plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-alerting-types'] --- import kbnSecuritysolutionIoTsAlertingTypesObj from './kbn_securitysolution_io_ts_alerting_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_list_types.mdx b/api_docs/kbn_securitysolution_io_ts_list_types.mdx index c572a1ce3de72..e2595450c861f 100644 --- a/api_docs/kbn_securitysolution_io_ts_list_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_list_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-list-types title: "@kbn/securitysolution-io-ts-list-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-list-types plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-list-types'] --- import kbnSecuritysolutionIoTsListTypesObj from './kbn_securitysolution_io_ts_list_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_types.mdx b/api_docs/kbn_securitysolution_io_ts_types.mdx index a2e076c65d1fb..5277291524c0b 100644 --- a/api_docs/kbn_securitysolution_io_ts_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-types title: "@kbn/securitysolution-io-ts-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-types plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-types'] --- import kbnSecuritysolutionIoTsTypesObj from './kbn_securitysolution_io_ts_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_utils.mdx b/api_docs/kbn_securitysolution_io_ts_utils.mdx index e66309cab986b..bbc1e93212f85 100644 --- a/api_docs/kbn_securitysolution_io_ts_utils.mdx +++ b/api_docs/kbn_securitysolution_io_ts_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-utils title: "@kbn/securitysolution-io-ts-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-utils plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-utils'] --- import kbnSecuritysolutionIoTsUtilsObj from './kbn_securitysolution_io_ts_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_api.mdx b/api_docs/kbn_securitysolution_list_api.mdx index 35a57a3d6078a..f30630a64ff8f 100644 --- a/api_docs/kbn_securitysolution_list_api.mdx +++ b/api_docs/kbn_securitysolution_list_api.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-api title: "@kbn/securitysolution-list-api" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-api plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-api'] --- import kbnSecuritysolutionListApiObj from './kbn_securitysolution_list_api.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_constants.mdx b/api_docs/kbn_securitysolution_list_constants.mdx index 63afb89f8fee0..298cefe3ae110 100644 --- a/api_docs/kbn_securitysolution_list_constants.mdx +++ b/api_docs/kbn_securitysolution_list_constants.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-constants title: "@kbn/securitysolution-list-constants" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-constants plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-constants'] --- import kbnSecuritysolutionListConstantsObj from './kbn_securitysolution_list_constants.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_hooks.mdx b/api_docs/kbn_securitysolution_list_hooks.mdx index 4ea6135b018d4..aec81fded795b 100644 --- a/api_docs/kbn_securitysolution_list_hooks.mdx +++ b/api_docs/kbn_securitysolution_list_hooks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-hooks title: "@kbn/securitysolution-list-hooks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-hooks plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-hooks'] --- import kbnSecuritysolutionListHooksObj from './kbn_securitysolution_list_hooks.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_utils.mdx b/api_docs/kbn_securitysolution_list_utils.mdx index 5a9ad6150157a..df6ce1a9325d5 100644 --- a/api_docs/kbn_securitysolution_list_utils.mdx +++ b/api_docs/kbn_securitysolution_list_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-utils title: "@kbn/securitysolution-list-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-utils plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-utils'] --- import kbnSecuritysolutionListUtilsObj from './kbn_securitysolution_list_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_rules.mdx b/api_docs/kbn_securitysolution_rules.mdx index 8cf96bfc154bd..6fd1cc453392a 100644 --- a/api_docs/kbn_securitysolution_rules.mdx +++ b/api_docs/kbn_securitysolution_rules.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-rules title: "@kbn/securitysolution-rules" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-rules plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-rules'] --- import kbnSecuritysolutionRulesObj from './kbn_securitysolution_rules.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_t_grid.mdx b/api_docs/kbn_securitysolution_t_grid.mdx index 63c046237caf1..beb2e591dc3c4 100644 --- a/api_docs/kbn_securitysolution_t_grid.mdx +++ b/api_docs/kbn_securitysolution_t_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-t-grid title: "@kbn/securitysolution-t-grid" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-t-grid plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-t-grid'] --- import kbnSecuritysolutionTGridObj from './kbn_securitysolution_t_grid.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_utils.mdx b/api_docs/kbn_securitysolution_utils.mdx index ca6f7abd6e5b5..a36e09b63fd5a 100644 --- a/api_docs/kbn_securitysolution_utils.mdx +++ b/api_docs/kbn_securitysolution_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-utils title: "@kbn/securitysolution-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-utils plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-utils'] --- import kbnSecuritysolutionUtilsObj from './kbn_securitysolution_utils.devdocs.json'; diff --git a/api_docs/kbn_server_http_tools.devdocs.json b/api_docs/kbn_server_http_tools.devdocs.json index eb8ca2eeaa8b2..1fe0296f941f7 100644 --- a/api_docs/kbn_server_http_tools.devdocs.json +++ b/api_docs/kbn_server_http_tools.devdocs.json @@ -239,8 +239,6 @@ "signature": [ "(serverOptions: ", "ServerOptions", - ", listenerOptions: ", - "ListenerOptions", ") => ", "Server" ], @@ -262,21 +260,6 @@ "deprecated": false, "trackAdoption": false, "isRequired": true - }, - { - "parentPluginId": "@kbn/server-http-tools", - "id": "def-common.createServer.$2", - "type": "Object", - "tags": [], - "label": "listenerOptions", - "description": [], - "signature": [ - "ListenerOptions" - ], - "path": "packages/kbn-server-http-tools/src/create_server.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true } ], "returnComment": [], @@ -353,54 +336,6 @@ "returnComment": [], "initialIsOpen": false }, - { - "parentPluginId": "@kbn/server-http-tools", - "id": "def-common.getListenerOptions", - "type": "Function", - "tags": [], - "label": "getListenerOptions", - "description": [], - "signature": [ - "(config: ", - { - "pluginId": "@kbn/server-http-tools", - "scope": "common", - "docId": "kibKbnServerHttpToolsPluginApi", - "section": "def-common.IHttpConfig", - "text": "IHttpConfig" - }, - ") => ", - "ListenerOptions" - ], - "path": "packages/kbn-server-http-tools/src/get_listener_options.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/server-http-tools", - "id": "def-common.getListenerOptions.$1", - "type": "Object", - "tags": [], - "label": "config", - "description": [], - "signature": [ - { - "pluginId": "@kbn/server-http-tools", - "scope": "common", - "docId": "kibKbnServerHttpToolsPluginApi", - "section": "def-common.IHttpConfig", - "text": "IHttpConfig" - } - ], - "path": "packages/kbn-server-http-tools/src/get_listener_options.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - }, { "parentPluginId": "@kbn/server-http-tools", "id": "def-common.getRequestId", @@ -474,6 +409,69 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/server-http-tools", + "id": "def-common.getServerListener", + "type": "Function", + "tags": [], + "label": "getServerListener", + "description": [], + "signature": [ + "(config: ", + { + "pluginId": "@kbn/server-http-tools", + "scope": "common", + "docId": "kibKbnServerHttpToolsPluginApi", + "section": "def-common.IHttpConfig", + "text": "IHttpConfig" + }, + ", options: GetServerListenerOptions) => ", + "ServerListener" + ], + "path": "packages/kbn-server-http-tools/src/get_listener.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/server-http-tools", + "id": "def-common.getServerListener.$1", + "type": "Object", + "tags": [], + "label": "config", + "description": [], + "signature": [ + { + "pluginId": "@kbn/server-http-tools", + "scope": "common", + "docId": "kibKbnServerHttpToolsPluginApi", + "section": "def-common.IHttpConfig", + "text": "IHttpConfig" + } + ], + "path": "packages/kbn-server-http-tools/src/get_listener.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/server-http-tools", + "id": "def-common.getServerListener.$2", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "GetServerListenerOptions" + ], + "path": "packages/kbn-server-http-tools/src/get_listener.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/server-http-tools", "id": "def-common.getServerOptions", @@ -565,7 +563,7 @@ "ServerResponse", "> | undefined" ], - "path": "packages/kbn-server-http-tools/src/get_server_options.ts", + "path": "packages/kbn-server-http-tools/src/get_tls_options.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -585,7 +583,7 @@ "text": "ISslConfig" } ], - "path": "packages/kbn-server-http-tools/src/get_server_options.ts", + "path": "packages/kbn-server-http-tools/src/get_tls_options.ts", "deprecated": false, "trackAdoption": false, "isRequired": true diff --git a/api_docs/kbn_server_http_tools.mdx b/api_docs/kbn_server_http_tools.mdx index f34a671c1a48c..9c488d354924e 100644 --- a/api_docs/kbn_server_http_tools.mdx +++ b/api_docs/kbn_server_http_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-http-tools title: "@kbn/server-http-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-http-tools plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-http-tools'] --- import kbnServerHttpToolsObj from './kbn_server_http_tools.devdocs.json'; diff --git a/api_docs/kbn_server_route_repository.mdx b/api_docs/kbn_server_route_repository.mdx index 01e8f7843532e..fd173ded4b36d 100644 --- a/api_docs/kbn_server_route_repository.mdx +++ b/api_docs/kbn_server_route_repository.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-route-repository title: "@kbn/server-route-repository" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-route-repository plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository'] --- import kbnServerRouteRepositoryObj from './kbn_server_route_repository.devdocs.json'; diff --git a/api_docs/kbn_serverless_common_settings.mdx b/api_docs/kbn_serverless_common_settings.mdx index 745260e4a94f8..065642217dbf7 100644 --- a/api_docs/kbn_serverless_common_settings.mdx +++ b/api_docs/kbn_serverless_common_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-common-settings title: "@kbn/serverless-common-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-common-settings plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-common-settings'] --- import kbnServerlessCommonSettingsObj from './kbn_serverless_common_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_observability_settings.mdx b/api_docs/kbn_serverless_observability_settings.mdx index d9c17089ddc89..08fba0f68df68 100644 --- a/api_docs/kbn_serverless_observability_settings.mdx +++ b/api_docs/kbn_serverless_observability_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-observability-settings title: "@kbn/serverless-observability-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-observability-settings plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-observability-settings'] --- import kbnServerlessObservabilitySettingsObj from './kbn_serverless_observability_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_project_switcher.mdx b/api_docs/kbn_serverless_project_switcher.mdx index a5b47a9080ee1..081baa9e59ba1 100644 --- a/api_docs/kbn_serverless_project_switcher.mdx +++ b/api_docs/kbn_serverless_project_switcher.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-project-switcher title: "@kbn/serverless-project-switcher" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-project-switcher plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-project-switcher'] --- import kbnServerlessProjectSwitcherObj from './kbn_serverless_project_switcher.devdocs.json'; diff --git a/api_docs/kbn_serverless_search_settings.mdx b/api_docs/kbn_serverless_search_settings.mdx index b89a43151117a..f5203782cf427 100644 --- a/api_docs/kbn_serverless_search_settings.mdx +++ b/api_docs/kbn_serverless_search_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-search-settings title: "@kbn/serverless-search-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-search-settings plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-search-settings'] --- import kbnServerlessSearchSettingsObj from './kbn_serverless_search_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_security_settings.mdx b/api_docs/kbn_serverless_security_settings.mdx index 4b79a918b03e8..d0d880d9382ca 100644 --- a/api_docs/kbn_serverless_security_settings.mdx +++ b/api_docs/kbn_serverless_security_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-security-settings title: "@kbn/serverless-security-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-security-settings plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-security-settings'] --- import kbnServerlessSecuritySettingsObj from './kbn_serverless_security_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_storybook_config.mdx b/api_docs/kbn_serverless_storybook_config.mdx index d239e446791a4..f2d869e311144 100644 --- a/api_docs/kbn_serverless_storybook_config.mdx +++ b/api_docs/kbn_serverless_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-storybook-config title: "@kbn/serverless-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-storybook-config plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-storybook-config'] --- import kbnServerlessStorybookConfigObj from './kbn_serverless_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_shared_svg.mdx b/api_docs/kbn_shared_svg.mdx index 0659128adf42d..a416ee75325eb 100644 --- a/api_docs/kbn_shared_svg.mdx +++ b/api_docs/kbn_shared_svg.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-svg title: "@kbn/shared-svg" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-svg plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-svg'] --- import kbnSharedSvgObj from './kbn_shared_svg.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_avatar_solution.mdx b/api_docs/kbn_shared_ux_avatar_solution.mdx index 21f93739bcc4e..e3061a15ace28 100644 --- a/api_docs/kbn_shared_ux_avatar_solution.mdx +++ b/api_docs/kbn_shared_ux_avatar_solution.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-avatar-solution title: "@kbn/shared-ux-avatar-solution" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-avatar-solution plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-avatar-solution'] --- import kbnSharedUxAvatarSolutionObj from './kbn_shared_ux_avatar_solution.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_exit_full_screen.mdx b/api_docs/kbn_shared_ux_button_exit_full_screen.mdx index 62a7052d3e130..866c0af480932 100644 --- a/api_docs/kbn_shared_ux_button_exit_full_screen.mdx +++ b/api_docs/kbn_shared_ux_button_exit_full_screen.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-exit-full-screen title: "@kbn/shared-ux-button-exit-full-screen" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-exit-full-screen plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-exit-full-screen'] --- import kbnSharedUxButtonExitFullScreenObj from './kbn_shared_ux_button_exit_full_screen.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_toolbar.mdx b/api_docs/kbn_shared_ux_button_toolbar.mdx index 8bc05e22be7ef..f3b59a8ee4a5b 100644 --- a/api_docs/kbn_shared_ux_button_toolbar.mdx +++ b/api_docs/kbn_shared_ux_button_toolbar.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-toolbar title: "@kbn/shared-ux-button-toolbar" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-toolbar plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-toolbar'] --- import kbnSharedUxButtonToolbarObj from './kbn_shared_ux_button_toolbar.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_card_no_data.mdx b/api_docs/kbn_shared_ux_card_no_data.mdx index 153598bbb2a55..cd06f81bd788d 100644 --- a/api_docs/kbn_shared_ux_card_no_data.mdx +++ b/api_docs/kbn_shared_ux_card_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data title: "@kbn/shared-ux-card-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-card-no-data plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data'] --- import kbnSharedUxCardNoDataObj from './kbn_shared_ux_card_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_card_no_data_mocks.mdx b/api_docs/kbn_shared_ux_card_no_data_mocks.mdx index f819a384e2403..dc0ad5799ae7c 100644 --- a/api_docs/kbn_shared_ux_card_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_card_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data-mocks title: "@kbn/shared-ux-card-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-card-no-data-mocks plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data-mocks'] --- import kbnSharedUxCardNoDataMocksObj from './kbn_shared_ux_card_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_chrome_navigation.mdx b/api_docs/kbn_shared_ux_chrome_navigation.mdx index 1618dea67537d..0b4203089296a 100644 --- a/api_docs/kbn_shared_ux_chrome_navigation.mdx +++ b/api_docs/kbn_shared_ux_chrome_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-chrome-navigation title: "@kbn/shared-ux-chrome-navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-chrome-navigation plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-chrome-navigation'] --- import kbnSharedUxChromeNavigationObj from './kbn_shared_ux_chrome_navigation.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_error_boundary.mdx b/api_docs/kbn_shared_ux_error_boundary.mdx index d265a68b65e4c..990444efe7397 100644 --- a/api_docs/kbn_shared_ux_error_boundary.mdx +++ b/api_docs/kbn_shared_ux_error_boundary.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-error-boundary title: "@kbn/shared-ux-error-boundary" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-error-boundary plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-error-boundary'] --- import kbnSharedUxErrorBoundaryObj from './kbn_shared_ux_error_boundary.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_context.mdx b/api_docs/kbn_shared_ux_file_context.mdx index 18f0b044001b1..e4df22a79d17d 100644 --- a/api_docs/kbn_shared_ux_file_context.mdx +++ b/api_docs/kbn_shared_ux_file_context.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-context title: "@kbn/shared-ux-file-context" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-context plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-context'] --- import kbnSharedUxFileContextObj from './kbn_shared_ux_file_context.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_image.mdx b/api_docs/kbn_shared_ux_file_image.mdx index b2fedf50c82d0..99e0451726ba1 100644 --- a/api_docs/kbn_shared_ux_file_image.mdx +++ b/api_docs/kbn_shared_ux_file_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-image title: "@kbn/shared-ux-file-image" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-image plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-image'] --- import kbnSharedUxFileImageObj from './kbn_shared_ux_file_image.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_image_mocks.mdx b/api_docs/kbn_shared_ux_file_image_mocks.mdx index 6ffe0d1b1930f..e9cd287234754 100644 --- a/api_docs/kbn_shared_ux_file_image_mocks.mdx +++ b/api_docs/kbn_shared_ux_file_image_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-image-mocks title: "@kbn/shared-ux-file-image-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-image-mocks plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-image-mocks'] --- import kbnSharedUxFileImageMocksObj from './kbn_shared_ux_file_image_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_mocks.mdx b/api_docs/kbn_shared_ux_file_mocks.mdx index 2fdf7b0760c59..807e6b6b25773 100644 --- a/api_docs/kbn_shared_ux_file_mocks.mdx +++ b/api_docs/kbn_shared_ux_file_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-mocks title: "@kbn/shared-ux-file-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-mocks plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-mocks'] --- import kbnSharedUxFileMocksObj from './kbn_shared_ux_file_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_picker.mdx b/api_docs/kbn_shared_ux_file_picker.mdx index 682990dc1a483..a5c99a1bec6ba 100644 --- a/api_docs/kbn_shared_ux_file_picker.mdx +++ b/api_docs/kbn_shared_ux_file_picker.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-picker title: "@kbn/shared-ux-file-picker" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-picker plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-picker'] --- import kbnSharedUxFilePickerObj from './kbn_shared_ux_file_picker.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_types.mdx b/api_docs/kbn_shared_ux_file_types.mdx index 6e66f71e5d71b..6eb8158323c5d 100644 --- a/api_docs/kbn_shared_ux_file_types.mdx +++ b/api_docs/kbn_shared_ux_file_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-types title: "@kbn/shared-ux-file-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-types plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-types'] --- import kbnSharedUxFileTypesObj from './kbn_shared_ux_file_types.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_upload.mdx b/api_docs/kbn_shared_ux_file_upload.mdx index 32692d3f3b59e..57a13b3ca3efe 100644 --- a/api_docs/kbn_shared_ux_file_upload.mdx +++ b/api_docs/kbn_shared_ux_file_upload.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-upload title: "@kbn/shared-ux-file-upload" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-upload plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-upload'] --- import kbnSharedUxFileUploadObj from './kbn_shared_ux_file_upload.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_util.mdx b/api_docs/kbn_shared_ux_file_util.mdx index a1c70d25a2527..0f9d7cedbce6a 100644 --- a/api_docs/kbn_shared_ux_file_util.mdx +++ b/api_docs/kbn_shared_ux_file_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-util title: "@kbn/shared-ux-file-util" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-util plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-util'] --- import kbnSharedUxFileUtilObj from './kbn_shared_ux_file_util.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_link_redirect_app.mdx b/api_docs/kbn_shared_ux_link_redirect_app.mdx index 591bb419eef5a..3ad2a27224148 100644 --- a/api_docs/kbn_shared_ux_link_redirect_app.mdx +++ b/api_docs/kbn_shared_ux_link_redirect_app.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-link-redirect-app title: "@kbn/shared-ux-link-redirect-app" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-link-redirect-app plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-link-redirect-app'] --- import kbnSharedUxLinkRedirectAppObj from './kbn_shared_ux_link_redirect_app.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx index c4ad07d9702e6..574ef69da379c 100644 --- a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx +++ b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-link-redirect-app-mocks title: "@kbn/shared-ux-link-redirect-app-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-link-redirect-app-mocks plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-link-redirect-app-mocks'] --- import kbnSharedUxLinkRedirectAppMocksObj from './kbn_shared_ux_link_redirect_app_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_markdown.mdx b/api_docs/kbn_shared_ux_markdown.mdx index 27828e3a97c76..61913cbfb0c2b 100644 --- a/api_docs/kbn_shared_ux_markdown.mdx +++ b/api_docs/kbn_shared_ux_markdown.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-markdown title: "@kbn/shared-ux-markdown" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-markdown plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-markdown'] --- import kbnSharedUxMarkdownObj from './kbn_shared_ux_markdown.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_markdown_mocks.mdx b/api_docs/kbn_shared_ux_markdown_mocks.mdx index 824cd38f2b0b1..82ef7d9ea6d25 100644 --- a/api_docs/kbn_shared_ux_markdown_mocks.mdx +++ b/api_docs/kbn_shared_ux_markdown_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-markdown-mocks title: "@kbn/shared-ux-markdown-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-markdown-mocks plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-markdown-mocks'] --- import kbnSharedUxMarkdownMocksObj from './kbn_shared_ux_markdown_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx index 58368a6162f8d..d2e0058d62472 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data title: "@kbn/shared-ux-page-analytics-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-analytics-no-data plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-analytics-no-data'] --- import kbnSharedUxPageAnalyticsNoDataObj from './kbn_shared_ux_page_analytics_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx index 14c974ba11a34..ad639b964c0e9 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data-mocks title: "@kbn/shared-ux-page-analytics-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-analytics-no-data-mocks plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-analytics-no-data-mocks'] --- import kbnSharedUxPageAnalyticsNoDataMocksObj from './kbn_shared_ux_page_analytics_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_no_data.mdx b/api_docs/kbn_shared_ux_page_kibana_no_data.mdx index 87eb0d4ae5c7b..f73ac7be97937 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data title: "@kbn/shared-ux-page-kibana-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-no-data plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-no-data'] --- import kbnSharedUxPageKibanaNoDataObj from './kbn_shared_ux_page_kibana_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx index 9d8a19a7c71c7..2673f883acbae 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data-mocks title: "@kbn/shared-ux-page-kibana-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-no-data-mocks plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-no-data-mocks'] --- import kbnSharedUxPageKibanaNoDataMocksObj from './kbn_shared_ux_page_kibana_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_template.mdx b/api_docs/kbn_shared_ux_page_kibana_template.mdx index e48dcb987f647..d82646ee271d0 100644 --- a/api_docs/kbn_shared_ux_page_kibana_template.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_template.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-template title: "@kbn/shared-ux-page-kibana-template" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-template plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-template'] --- import kbnSharedUxPageKibanaTemplateObj from './kbn_shared_ux_page_kibana_template.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx b/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx index 567f2431b390c..e2fb5cfc61368 100644 --- a/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-template-mocks title: "@kbn/shared-ux-page-kibana-template-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-template-mocks plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-template-mocks'] --- import kbnSharedUxPageKibanaTemplateMocksObj from './kbn_shared_ux_page_kibana_template_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data.mdx b/api_docs/kbn_shared_ux_page_no_data.mdx index 8887812c45027..450f392601e2d 100644 --- a/api_docs/kbn_shared_ux_page_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data title: "@kbn/shared-ux-page-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data'] --- import kbnSharedUxPageNoDataObj from './kbn_shared_ux_page_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data_config.mdx b/api_docs/kbn_shared_ux_page_no_data_config.mdx index b7fd2434c980b..3a375d5dfcd09 100644 --- a/api_docs/kbn_shared_ux_page_no_data_config.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-config title: "@kbn/shared-ux-page-no-data-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-config plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data-config'] --- import kbnSharedUxPageNoDataConfigObj from './kbn_shared_ux_page_no_data_config.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx b/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx index 22946e98f94b9..b1bd70b8e216d 100644 --- a/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-config-mocks title: "@kbn/shared-ux-page-no-data-config-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-config-mocks plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data-config-mocks'] --- import kbnSharedUxPageNoDataConfigMocksObj from './kbn_shared_ux_page_no_data_config_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_no_data_mocks.mdx index 3732f6e44771d..ef59f46d726a3 100644 --- a/api_docs/kbn_shared_ux_page_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-mocks title: "@kbn/shared-ux-page-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-mocks plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data-mocks'] --- import kbnSharedUxPageNoDataMocksObj from './kbn_shared_ux_page_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_solution_nav.mdx b/api_docs/kbn_shared_ux_page_solution_nav.mdx index 67406176211cd..d727a2a03bc34 100644 --- a/api_docs/kbn_shared_ux_page_solution_nav.mdx +++ b/api_docs/kbn_shared_ux_page_solution_nav.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-solution-nav title: "@kbn/shared-ux-page-solution-nav" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-solution-nav plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-solution-nav'] --- import kbnSharedUxPageSolutionNavObj from './kbn_shared_ux_page_solution_nav.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx index 919798b6b1de3..b64d1b64526db 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views title: "@kbn/shared-ux-prompt-no-data-views" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-no-data-views plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-no-data-views'] --- import kbnSharedUxPromptNoDataViewsObj from './kbn_shared_ux_prompt_no_data_views.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx b/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx index 7394c69d76951..c34d0ef5daa9f 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views-mocks title: "@kbn/shared-ux-prompt-no-data-views-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-no-data-views-mocks plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-no-data-views-mocks'] --- import kbnSharedUxPromptNoDataViewsMocksObj from './kbn_shared_ux_prompt_no_data_views_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_not_found.mdx b/api_docs/kbn_shared_ux_prompt_not_found.mdx index f9d71f1f23424..2ccbe76559fa7 100644 --- a/api_docs/kbn_shared_ux_prompt_not_found.mdx +++ b/api_docs/kbn_shared_ux_prompt_not_found.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-not-found title: "@kbn/shared-ux-prompt-not-found" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-not-found plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-not-found'] --- import kbnSharedUxPromptNotFoundObj from './kbn_shared_ux_prompt_not_found.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_router.mdx b/api_docs/kbn_shared_ux_router.mdx index 59886686b30d6..7905a23d85679 100644 --- a/api_docs/kbn_shared_ux_router.mdx +++ b/api_docs/kbn_shared_ux_router.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-router title: "@kbn/shared-ux-router" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-router plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-router'] --- import kbnSharedUxRouterObj from './kbn_shared_ux_router.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_router_mocks.mdx b/api_docs/kbn_shared_ux_router_mocks.mdx index 9def918de0020..fb28bdacb3cd8 100644 --- a/api_docs/kbn_shared_ux_router_mocks.mdx +++ b/api_docs/kbn_shared_ux_router_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-router-mocks title: "@kbn/shared-ux-router-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-router-mocks plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-router-mocks'] --- import kbnSharedUxRouterMocksObj from './kbn_shared_ux_router_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_storybook_config.mdx b/api_docs/kbn_shared_ux_storybook_config.mdx index 041e9720f7984..a29b10b8cdbce 100644 --- a/api_docs/kbn_shared_ux_storybook_config.mdx +++ b/api_docs/kbn_shared_ux_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook-config title: "@kbn/shared-ux-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-storybook-config plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-storybook-config'] --- import kbnSharedUxStorybookConfigObj from './kbn_shared_ux_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_storybook_mock.mdx b/api_docs/kbn_shared_ux_storybook_mock.mdx index d635489810956..0512d68af41dd 100644 --- a/api_docs/kbn_shared_ux_storybook_mock.mdx +++ b/api_docs/kbn_shared_ux_storybook_mock.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook-mock title: "@kbn/shared-ux-storybook-mock" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-storybook-mock plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-storybook-mock'] --- import kbnSharedUxStorybookMockObj from './kbn_shared_ux_storybook_mock.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_tabbed_modal.mdx b/api_docs/kbn_shared_ux_tabbed_modal.mdx index c92a246c73fd5..8ec6e15629cf2 100644 --- a/api_docs/kbn_shared_ux_tabbed_modal.mdx +++ b/api_docs/kbn_shared_ux_tabbed_modal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-tabbed-modal title: "@kbn/shared-ux-tabbed-modal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-tabbed-modal plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-tabbed-modal'] --- import kbnSharedUxTabbedModalObj from './kbn_shared_ux_tabbed_modal.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_utility.mdx b/api_docs/kbn_shared_ux_utility.mdx index 37fd11222f5f7..934702e3c90b6 100644 --- a/api_docs/kbn_shared_ux_utility.mdx +++ b/api_docs/kbn_shared_ux_utility.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-utility title: "@kbn/shared-ux-utility" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-utility plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-utility'] --- import kbnSharedUxUtilityObj from './kbn_shared_ux_utility.devdocs.json'; diff --git a/api_docs/kbn_slo_schema.mdx b/api_docs/kbn_slo_schema.mdx index de52d4d13f3b1..c75b1e7c072b5 100644 --- a/api_docs/kbn_slo_schema.mdx +++ b/api_docs/kbn_slo_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-slo-schema title: "@kbn/slo-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/slo-schema plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/slo-schema'] --- import kbnSloSchemaObj from './kbn_slo_schema.devdocs.json'; diff --git a/api_docs/kbn_solution_nav_es.mdx b/api_docs/kbn_solution_nav_es.mdx index a6aeaf2d1ce3c..e35fb06ae8a63 100644 --- a/api_docs/kbn_solution_nav_es.mdx +++ b/api_docs/kbn_solution_nav_es.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-solution-nav-es title: "@kbn/solution-nav-es" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/solution-nav-es plugin -date: 2024-05-20 +date: 2024-05-22 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/solution-nav-es'] --- import kbnSolutionNavEsObj from './kbn_solution_nav_es.devdocs.json'; diff --git a/api_docs/kbn_solution_nav_oblt.mdx b/api_docs/kbn_solution_nav_oblt.mdx index dadd3bdcfcf29..e065603415c57 100644 --- a/api_docs/kbn_solution_nav_oblt.mdx +++ b/api_docs/kbn_solution_nav_oblt.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-solution-nav-oblt title: "@kbn/solution-nav-oblt" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/solution-nav-oblt plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/solution-nav-oblt'] --- import kbnSolutionNavObltObj from './kbn_solution_nav_oblt.devdocs.json'; diff --git a/api_docs/kbn_some_dev_log.mdx b/api_docs/kbn_some_dev_log.mdx index 01879167d24fa..026fa183f1407 100644 --- a/api_docs/kbn_some_dev_log.mdx +++ b/api_docs/kbn_some_dev_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-some-dev-log title: "@kbn/some-dev-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/some-dev-log plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/some-dev-log'] --- import kbnSomeDevLogObj from './kbn_some_dev_log.devdocs.json'; diff --git a/api_docs/kbn_sort_predicates.mdx b/api_docs/kbn_sort_predicates.mdx index 508f27f6014b1..1c8fc7f301cec 100644 --- a/api_docs/kbn_sort_predicates.mdx +++ b/api_docs/kbn_sort_predicates.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-sort-predicates title: "@kbn/sort-predicates" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/sort-predicates plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/sort-predicates'] --- import kbnSortPredicatesObj from './kbn_sort_predicates.devdocs.json'; diff --git a/api_docs/kbn_std.mdx b/api_docs/kbn_std.mdx index ac15d2dd748cf..7a6dda7a5826d 100644 --- a/api_docs/kbn_std.mdx +++ b/api_docs/kbn_std.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-std title: "@kbn/std" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/std plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/std'] --- import kbnStdObj from './kbn_std.devdocs.json'; diff --git a/api_docs/kbn_stdio_dev_helpers.mdx b/api_docs/kbn_stdio_dev_helpers.mdx index 941fa8455045d..a514b56570c00 100644 --- a/api_docs/kbn_stdio_dev_helpers.mdx +++ b/api_docs/kbn_stdio_dev_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-stdio-dev-helpers title: "@kbn/stdio-dev-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/stdio-dev-helpers plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/stdio-dev-helpers'] --- import kbnStdioDevHelpersObj from './kbn_stdio_dev_helpers.devdocs.json'; diff --git a/api_docs/kbn_storybook.mdx b/api_docs/kbn_storybook.mdx index fed8552a412dc..db81779e51b54 100644 --- a/api_docs/kbn_storybook.mdx +++ b/api_docs/kbn_storybook.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-storybook title: "@kbn/storybook" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/storybook plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/storybook'] --- import kbnStorybookObj from './kbn_storybook.devdocs.json'; diff --git a/api_docs/kbn_telemetry_tools.mdx b/api_docs/kbn_telemetry_tools.mdx index f5e5d74c37a4f..f8619318c72c1 100644 --- a/api_docs/kbn_telemetry_tools.mdx +++ b/api_docs/kbn_telemetry_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-telemetry-tools title: "@kbn/telemetry-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/telemetry-tools plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/telemetry-tools'] --- import kbnTelemetryToolsObj from './kbn_telemetry_tools.devdocs.json'; diff --git a/api_docs/kbn_test.mdx b/api_docs/kbn_test.mdx index 3e987fbad81eb..2cd2dc3a53318 100644 --- a/api_docs/kbn_test.mdx +++ b/api_docs/kbn_test.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test title: "@kbn/test" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test'] --- import kbnTestObj from './kbn_test.devdocs.json'; diff --git a/api_docs/kbn_test_eui_helpers.mdx b/api_docs/kbn_test_eui_helpers.mdx index fde3359592ba7..150f310499243 100644 --- a/api_docs/kbn_test_eui_helpers.mdx +++ b/api_docs/kbn_test_eui_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-eui-helpers title: "@kbn/test-eui-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-eui-helpers plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-eui-helpers'] --- import kbnTestEuiHelpersObj from './kbn_test_eui_helpers.devdocs.json'; diff --git a/api_docs/kbn_test_jest_helpers.mdx b/api_docs/kbn_test_jest_helpers.mdx index 9ef0f4ff4cb60..055f8505efa56 100644 --- a/api_docs/kbn_test_jest_helpers.mdx +++ b/api_docs/kbn_test_jest_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-jest-helpers title: "@kbn/test-jest-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-jest-helpers plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-jest-helpers'] --- import kbnTestJestHelpersObj from './kbn_test_jest_helpers.devdocs.json'; diff --git a/api_docs/kbn_test_subj_selector.mdx b/api_docs/kbn_test_subj_selector.mdx index 7b652eb750e23..d26e41974e9b3 100644 --- a/api_docs/kbn_test_subj_selector.mdx +++ b/api_docs/kbn_test_subj_selector.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-subj-selector title: "@kbn/test-subj-selector" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-subj-selector plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-subj-selector'] --- import kbnTestSubjSelectorObj from './kbn_test_subj_selector.devdocs.json'; diff --git a/api_docs/kbn_text_based_editor.mdx b/api_docs/kbn_text_based_editor.mdx index 0db2cf9271d3d..38bc8847884d5 100644 --- a/api_docs/kbn_text_based_editor.mdx +++ b/api_docs/kbn_text_based_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-text-based-editor title: "@kbn/text-based-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/text-based-editor plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/text-based-editor'] --- import kbnTextBasedEditorObj from './kbn_text_based_editor.devdocs.json'; diff --git a/api_docs/kbn_timerange.mdx b/api_docs/kbn_timerange.mdx index cbe053404428e..2a643aac60323 100644 --- a/api_docs/kbn_timerange.mdx +++ b/api_docs/kbn_timerange.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-timerange title: "@kbn/timerange" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/timerange plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/timerange'] --- import kbnTimerangeObj from './kbn_timerange.devdocs.json'; diff --git a/api_docs/kbn_tooling_log.mdx b/api_docs/kbn_tooling_log.mdx index 1607c7d6d7f03..ef4497625ba30 100644 --- a/api_docs/kbn_tooling_log.mdx +++ b/api_docs/kbn_tooling_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-tooling-log title: "@kbn/tooling-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/tooling-log plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/tooling-log'] --- import kbnToolingLogObj from './kbn_tooling_log.devdocs.json'; diff --git a/api_docs/kbn_triggers_actions_ui_types.mdx b/api_docs/kbn_triggers_actions_ui_types.mdx index 98bf9927a42a3..3e2dde92fae7b 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/triggers-actions-ui-types'] --- import kbnTriggersActionsUiTypesObj from './kbn_triggers_actions_ui_types.devdocs.json'; diff --git a/api_docs/kbn_try_in_console.mdx b/api_docs/kbn_try_in_console.mdx index 6e28c672fca2a..0c55531eb3372 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-05-20 +date: 2024-05-23 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 fd2243c251a09..3f9fd09e824b2 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-05-20 +date: 2024-05-23 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 9cb2ec1eda367..75c241aebbd8e 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-05-20 +date: 2024-05-23 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 653baa42b1a7c..e2df6b4ff8daf 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-05-20 +date: 2024-05-23 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 b59daa1a3d4ed..5641c7657f235 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-05-20 +date: 2024-05-23 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 27f5011c2f861..74bebb3462db0 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-05-20 +date: 2024-05-23 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.mdx b/api_docs/kbn_unified_data_table.mdx index b3b3f0aa1b648..9ad3729fcea12 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-05-20 +date: 2024-05-23 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 8072d683064a0..f4884ebea7f55 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-05-20 +date: 2024-05-23 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 7efe0795b8e9a..0b81540944ce4 100644 --- a/api_docs/kbn_unified_field_list.devdocs.json +++ b/api_docs/kbn_unified_field_list.devdocs.json @@ -312,8 +312,8 @@ "pluginId": "@kbn/unified-field-list", "scope": "common", "docId": "kibKbnUnifiedFieldListPluginApi", - "section": "def-common.FieldPopoverFooterProps", - "text": "FieldPopoverFooterProps" + "section": "def-common.FieldVisualizeButtonProps", + "text": "FieldVisualizeButtonProps" }, ">) => JSX.Element" ], @@ -334,8 +334,8 @@ "pluginId": "@kbn/unified-field-list", "scope": "common", "docId": "kibKbnUnifiedFieldListPluginApi", - "section": "def-common.FieldPopoverFooterProps", - "text": "FieldPopoverFooterProps" + "section": "def-common.FieldVisualizeButtonProps", + "text": "FieldVisualizeButtonProps" }, ">" ], @@ -5486,9 +5486,7 @@ "docId": "kibKbnUnifiedFieldListPluginApi", "section": "def-common.FieldVisualizeButtonProps", "text": "FieldVisualizeButtonProps" - }, - " | ", - "FieldCategorizeButtonProps" + } ], "path": "packages/kbn-unified-field-list/src/components/field_popover/field_popover_footer.tsx", "deprecated": false, diff --git a/api_docs/kbn_unified_field_list.mdx b/api_docs/kbn_unified_field_list.mdx index 81be1b3177f53..a2e4dbccad3cc 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-05-20 +date: 2024-05-23 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 | |-------------------|-----------|------------------------|-----------------| -| 293 | 0 | 269 | 10 | +| 293 | 0 | 269 | 9 | ## Common diff --git a/api_docs/kbn_unsaved_changes_badge.mdx b/api_docs/kbn_unsaved_changes_badge.mdx index 63f58848e66ff..7110631c73fc0 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unsaved-changes-badge'] --- import kbnUnsavedChangesBadgeObj from './kbn_unsaved_changes_badge.devdocs.json'; diff --git a/api_docs/kbn_use_tracked_promise.mdx b/api_docs/kbn_use_tracked_promise.mdx index ac7a20c6b72e6..f270dd3c51097 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-05-20 +date: 2024-05-23 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.devdocs.json b/api_docs/kbn_user_profile_components.devdocs.json index 860936ef0b970..c7c080c2e335a 100644 --- a/api_docs/kbn_user_profile_components.devdocs.json +++ b/api_docs/kbn_user_profile_components.devdocs.json @@ -1399,11 +1399,11 @@ "EuiSelectableLIOption", "<{}>> & ", "CommonProps", - " & { label: string; searchableLabel?: string | undefined; key?: string | undefined; checked?: ", - "EuiSelectableOptionCheckedType", - "; disabled?: boolean | undefined; isGroupLabel?: false | undefined; prepend?: React.ReactNode; append?: React.ReactNode; ref?: ((optionIndex: number) => void) | undefined; id?: undefined; data?: { [key: string]: any; } | undefined; textWrap?: \"wrap\" | \"truncate\" | undefined; truncationProps?: Partial void) | undefined; id?: undefined; data?: { [key: string]: any; } | undefined; textWrap?: \"wrap\" | \"truncate\" | undefined; truncationProps?: Partial> | undefined; } & React.HTMLAttributes) | (", + ", \"text\" | \"children\">> | undefined; toolTipContent?: React.ReactNode; toolTipProps?: Partial> | undefined; } & React.HTMLAttributes) | (", "DisambiguateSet", "<", "EuiSelectableLIOption", diff --git a/api_docs/kbn_user_profile_components.mdx b/api_docs/kbn_user_profile_components.mdx index db5b8249ff3ed..5ce35c98f2efb 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-05-20 +date: 2024-05-23 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 233ae9ef55e13..1a10c8e9dd964 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-05-20 +date: 2024-05-23 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 a762b3b6da30d..7004f9dbaa262 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-05-20 +date: 2024-05-23 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 726214f3a22d9..b26d2c796c748 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utils'] --- import kbnUtilsObj from './kbn_utils.devdocs.json'; diff --git a/api_docs/kbn_visualization_ui_components.devdocs.json b/api_docs/kbn_visualization_ui_components.devdocs.json index 329e0a16222f7..80f0cff7f6a2d 100644 --- a/api_docs/kbn_visualization_ui_components.devdocs.json +++ b/api_docs/kbn_visualization_ui_components.devdocs.json @@ -948,15 +948,13 @@ "label": "dataView", "description": [], "signature": [ - "{ fields: ", { "pluginId": "@kbn/es-query", "scope": "common", "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.DataViewFieldBase", - "text": "DataViewFieldBase" - }, - "[]; id?: string | undefined; title: string; }" + "section": "def-common.DataViewBase", + "text": "DataViewBase" + } ], "path": "packages/kbn-visualization-ui-components/components/query_input/filter_query_input.tsx", "deprecated": false, diff --git a/api_docs/kbn_visualization_ui_components.mdx b/api_docs/kbn_visualization_ui_components.mdx index ba5a9aead9745..ec8de388ca7c7 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-05-20 +date: 2024-05-23 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 9f8cd210a3f24..eccca0a73401f 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-05-20 +date: 2024-05-23 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 a9fb8508b490c..9eb820c299c71 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-05-20 +date: 2024-05-23 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 abc9434abf530..0189f95f92885 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-05-20 +date: 2024-05-23 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 1fbdf0062a349..dd45a79b603f1 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-05-20 +date: 2024-05-23 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 1717c1602ba58..12fea21f21a27 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-05-20 +date: 2024-05-23 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 36a5c3cfd0e65..292e5851aec4d 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-05-20 +date: 2024-05-23 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 0aa15b1d04d41..ebc8fa5a5f358 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-05-20 +date: 2024-05-23 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 7f6ae788d2720..f59073f7edc60 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-05-20 +date: 2024-05-23 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 c3ef45609b022..430379fa18e9e 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-05-20 +date: 2024-05-23 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 df48c59479d8f..ad23e5e0f061a 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-05-20 +date: 2024-05-23 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 1ab460056ad87..999afa9ed4ce9 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-05-20 +date: 2024-05-23 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 2f482f3c45d9f..2fda7f95e1d9e 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-05-20 +date: 2024-05-23 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 99e3028a1874b..06ac83e03d662 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-05-20 +date: 2024-05-23 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 485ce19c77d8a..a6649e147655c 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-05-20 +date: 2024-05-23 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 9e95c7fceecda..fd05be02f80eb 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-05-20 +date: 2024-05-23 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 f45396785a08f..e4122048f599b 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-05-20 +date: 2024-05-23 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 485723b32754f..f6d46cd4e0902 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-05-20 +date: 2024-05-23 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 2111af1994ea7..2e489469f62ab 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-05-20 +date: 2024-05-23 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 6f79c80cff47a..adadc52d365b7 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-05-20 +date: 2024-05-23 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 07755a84b02c0..890c1398254ad 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-05-20 +date: 2024-05-23 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 9a9f33206fdf9..2e7c60a892fb7 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-05-20 +date: 2024-05-23 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 beaea76c533b7..babb3ee41c8c5 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-05-20 +date: 2024-05-23 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 2069056f50652..0b11c477115e5 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-05-20 +date: 2024-05-23 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 61b72c0aa45de..09d16e1bd1c07 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-05-20 +date: 2024-05-23 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 b2ca9d714ef6b..241abd2145208 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'monitoringCollection'] --- import monitoringCollectionObj from './monitoring_collection.devdocs.json'; diff --git a/api_docs/navigation.devdocs.json b/api_docs/navigation.devdocs.json index 9c386e01c71b1..27e000454c128 100644 --- a/api_docs/navigation.devdocs.json +++ b/api_docs/navigation.devdocs.json @@ -826,6 +826,31 @@ ], "enums": [], "misc": [ + { + "parentPluginId": "navigation", + "id": "def-public.AddSolutionNavigationArg", + "type": "Type", + "tags": [], + "label": "AddSolutionNavigationArg", + "description": [], + "signature": [ + "Omit<", + "SolutionNavigation", + ", \"sideNavComponent\"> & { dataTestSubj?: string | undefined; panelContentProvider?: ", + { + "pluginId": "@kbn/shared-ux-chrome-navigation", + "scope": "public", + "docId": "kibKbnSharedUxChromeNavigationPluginApi", + "section": "def-public.ContentProvider", + "text": "ContentProvider" + }, + " | undefined; }" + ], + "path": "src/plugins/navigation/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "navigation", "id": "def-public.SolutionType", @@ -1074,7 +1099,13 @@ ], "signature": [ "(solutionNavigationAgg: ", - "AddSolutionNavigationArg", + { + "pluginId": "navigation", + "scope": "public", + "docId": "kibNavigationPluginApi", + "section": "def-public.AddSolutionNavigationArg", + "text": "AddSolutionNavigationArg" + }, ") => void" ], "path": "src/plugins/navigation/public/types.ts", @@ -1089,7 +1120,13 @@ "label": "solutionNavigationAgg", "description": [], "signature": [ - "AddSolutionNavigationArg" + { + "pluginId": "navigation", + "scope": "public", + "docId": "kibNavigationPluginApi", + "section": "def-public.AddSolutionNavigationArg", + "text": "AddSolutionNavigationArg" + } ], "path": "src/plugins/navigation/public/types.ts", "deprecated": false, diff --git a/api_docs/navigation.mdx b/api_docs/navigation.mdx index cd5e7719b1521..59ecc7f918f21 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'navigation'] --- import navigationObj from './navigation.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 | |-------------------|-----------|------------------------|-----------------| -| 49 | 0 | 47 | 5 | +| 50 | 0 | 48 | 5 | ## Client diff --git a/api_docs/newsfeed.mdx b/api_docs/newsfeed.mdx index e7e8a84d0999e..e0dea1a366d98 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-05-20 +date: 2024-05-23 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 2bf4842d3aa9c..8b96d504772e9 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-05-20 +date: 2024-05-23 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 ab929eaca72a7..b26aeb094f724 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'notifications'] --- import notificationsObj from './notifications.devdocs.json'; diff --git a/api_docs/observability.devdocs.json b/api_docs/observability.devdocs.json index 977e46df309f5..2f6bf11d914de 100644 --- a/api_docs/observability.devdocs.json +++ b/api_docs/observability.devdocs.json @@ -3572,7 +3572,13 @@ "label": "aiops", "description": [], "signature": [ - "AiopsPluginStart" + { + "pluginId": "aiops", + "scope": "public", + "docId": "kibAiopsPluginApi", + "section": "def-public.AiopsPluginStart", + "text": "AiopsPluginStart" + } ], "path": "x-pack/plugins/observability_solution/observability/public/plugin.ts", "deprecated": false, diff --git a/api_docs/observability.mdx b/api_docs/observability.mdx index 94e78057415cb..21578f75741d1 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observability'] --- import observabilityObj from './observability.devdocs.json'; diff --git a/api_docs/observability_a_i_assistant.devdocs.json b/api_docs/observability_a_i_assistant.devdocs.json index c02bb4cb86da2..6952ef5f0ce24 100644 --- a/api_docs/observability_a_i_assistant.devdocs.json +++ b/api_docs/observability_a_i_assistant.devdocs.json @@ -3530,6 +3530,21 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "observabilityAIAssistant", + "id": "def-public.aiAssistantSearchConnectorIndexPattern", + "type": "string", + "tags": [], + "label": "aiAssistantSearchConnectorIndexPattern", + "description": [], + "signature": [ + "\"observability:aiAssistantSearchConnectorIndexPattern\"" + ], + "path": "x-pack/plugins/observability_solution/observability_ai_assistant/common/ui_settings/settings_keys.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "observabilityAIAssistant", "id": "def-public.aiAssistantSimulatedFunctionCalling", @@ -5668,6 +5683,21 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "observabilityAIAssistant", + "id": "def-server.aiAssistantSearchConnectorIndexPattern", + "type": "string", + "tags": [], + "label": "aiAssistantSearchConnectorIndexPattern", + "description": [], + "signature": [ + "\"observability:aiAssistantSearchConnectorIndexPattern\"" + ], + "path": "x-pack/plugins/observability_solution/observability_ai_assistant/common/ui_settings/settings_keys.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "observabilityAIAssistant", "id": "def-server.aiAssistantSimulatedFunctionCalling", @@ -7370,6 +7400,21 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "observabilityAIAssistant", + "id": "def-common.aiAssistantSearchConnectorIndexPattern", + "type": "string", + "tags": [], + "label": "aiAssistantSearchConnectorIndexPattern", + "description": [], + "signature": [ + "\"observability:aiAssistantSearchConnectorIndexPattern\"" + ], + "path": "x-pack/plugins/observability_solution/observability_ai_assistant/common/ui_settings/settings_keys.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "observabilityAIAssistant", "id": "def-common.aiAssistantSimulatedFunctionCalling", diff --git a/api_docs/observability_a_i_assistant.mdx b/api_docs/observability_a_i_assistant.mdx index 8bbd911ed4503..52c5a766a6c52 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityAIAssistant'] --- import observabilityAIAssistantObj from './observability_a_i_assistant.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 253 | 1 | 251 | 26 | +| 256 | 1 | 254 | 26 | ## Client diff --git a/api_docs/observability_a_i_assistant_app.mdx b/api_docs/observability_a_i_assistant_app.mdx index b11b636b3daa2..ab5f33e06aaf4 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-05-20 +date: 2024-05-23 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 d39fa52f9d2c2..05ffc71f9a870 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-05-20 +date: 2024-05-23 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 e7363949fffe8..ab4867bec4caa 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-05-20 +date: 2024-05-23 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 2f487c6187867..1a4d09fcf89c5 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-05-20 +date: 2024-05-23 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 d5a79adc57e03..1a076dc0ae454 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-05-20 +date: 2024-05-23 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 caeef587b92dd..4d3a4ee801b17 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-05-20 +date: 2024-05-23 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 f3994662ff5df..9e15ea5feb728 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-05-20 +date: 2024-05-23 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 5a6ccd7f4b458..d941215ea3f9c 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-05-20 +date: 2024-05-23 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 | |--------------|----------|------------------------| -| 797 | 685 | 43 | +| 797 | 684 | 42 | ### Public API health stats | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 48219 | 241 | 36798 | 1860 | +| 48345 | 241 | 36897 | 1863 | ## Plugin Directory @@ -30,7 +30,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 303 | 0 | 297 | 32 | | | [@elastic/appex-sharedux @elastic/kibana-management](https://github.com/orgs/elastic/teams/appex-sharedux ) | - | 2 | 0 | 2 | 0 | | | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | - | 4 | 0 | 4 | 1 | -| | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | AIOps plugin maintained by ML team. | 67 | 0 | 4 | 1 | +| | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | AIOps plugin maintained by ML team. | 74 | 0 | 9 | 2 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 865 | 1 | 833 | 54 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | The user interface for Elastic APM | 29 | 0 | 29 | 123 | | | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | - | 9 | 0 | 9 | 0 | @@ -43,7 +43,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 268 | 2 | 253 | 10 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 74 | 0 | 17 | 0 | | cloudChat | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | Chat available on Elastic Cloud deployments for quicker assistance. | 0 | 0 | 0 | 0 | -| | [@elastic/platform-onboarding](https://github.com/orgs/elastic/teams/platform-onboarding) | Static migration page where self-managed users can see text/copy about migrating to Elastic Cloud | 8 | 0 | 8 | 1 | +| | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | Static migration page where self-managed users can see text/copy about migrating to Elastic Cloud | 8 | 0 | 8 | 1 | | | [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic/teams/kibana-cloud-security-posture) | Defend for containers (D4C) | 52 | 0 | 43 | 2 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | Provides the necessary APIs to implement A/B testing scenarios, fetching the variations in configuration and reporting back metrics to track conversion rates of the experiments. | 12 | 0 | 0 | 0 | | cloudFullStory | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | When Kibana runs on Elastic Cloud, this plugin registers FullStory as a shipper for telemetry. | 0 | 0 | 0 | 0 | @@ -70,7 +70,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | A stateful layer to register shared features and provide an access point to discover without a direct dependency | 16 | 0 | 15 | 2 | | | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | APIs used to assess the quality of data in Elasticsearch indexes | 2 | 0 | 0 | 0 | | | [@elastic/security-generative-ai](https://github.com/orgs/elastic/teams/security-generative-ai) | Server APIs for the Elastic AI Assistant | 46 | 0 | 32 | 0 | -| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds embeddables service to Kibana | 564 | 1 | 454 | 8 | +| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds embeddables service to Kibana | 554 | 1 | 444 | 8 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Extends embeddable plugin with more functionality | 19 | 0 | 19 | 2 | | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides encryption and decryption utilities for saved objects containing sensitive information. | 53 | 0 | 46 | 1 | | | [@elastic/enterprise-search-frontend](https://github.com/orgs/elastic/teams/enterprise-search-frontend) | Adds dashboards for discovering and managing Enterprise Search products. | 5 | 0 | 5 | 0 | @@ -92,20 +92,20 @@ 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. | 177 | 0 | 166 | 13 | -| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Adds expression runtime to Kibana | 2217 | 17 | 1756 | 5 | +| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Adds expression runtime to Kibana | 2233 | 17 | 1763 | 6 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 235 | 0 | 99 | 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/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 | 2 | 0 | 2 | 0 | -| | [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) | - | 1305 | 5 | 1184 | 66 | +| | [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) | - | 1309 | 5 | 1188 | 66 | | 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 | | globalSearchProviders | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 0 | 0 | 0 | 0 | | graph | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 0 | 0 | 0 | 0 | | grokdebugger | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 0 | 0 | 0 | 0 | -| | [@elastic/platform-onboarding](https://github.com/orgs/elastic/teams/platform-onboarding) | Guided onboarding framework | 59 | 0 | 58 | 0 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Guided onboarding framework | 59 | 0 | 58 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 149 | 0 | 111 | 1 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Image embeddable | 1 | 0 | 1 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 4 | 0 | 4 | 0 | @@ -138,12 +138,12 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | - | 2 | 0 | 2 | 0 | | | [@elastic/stack-monitoring](https://github.com/orgs/elastic/teams/stack-monitoring) | - | 15 | 3 | 13 | 1 | | | [@elastic/stack-monitoring](https://github.com/orgs/elastic/teams/stack-monitoring) | - | 9 | 0 | 9 | 0 | -| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 49 | 0 | 47 | 5 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 50 | 0 | 48 | 5 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 17 | 0 | 17 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 3 | 0 | 3 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 1 | | | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 695 | 2 | 686 | 15 | -| | [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai-assistant) | - | 253 | 1 | 251 | 26 | +| | [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai-assistant) | - | 256 | 1 | 254 | 26 | | | [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai-assistant) | - | 2 | 0 | 2 | 0 | | | [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai-assistant) | - | 2 | 0 | 2 | 0 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | This plugin exposes and registers observability log consumption features. | 21 | 0 | 21 | 1 | @@ -297,7 +297,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 5 | 0 | 0 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 20 | 0 | 7 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 6 | 0 | 6 | 0 | -| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 205 | 0 | 99 | 0 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 206 | 0 | 99 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 3 | 0 | 3 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 4 | 0 | 4 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 8 | 0 | 8 | 0 | @@ -345,7 +345,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 7 | 0 | 7 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 48 | 7 | 48 | 6 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 13 | 0 | 13 | 1 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 483 | 2 | 193 | 0 | +| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 486 | 2 | 193 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 91 | 0 | 78 | 10 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 44 | 0 | 43 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 4 | 0 | 2 | 0 | @@ -453,7 +453,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 16 | 0 | 16 | 0 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 19 | 0 | 17 | 6 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 2 | 0 | 2 | 0 | -| | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 26 | 0 | 26 | 0 | +| | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 51 | 0 | 51 | 1 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 14 | 0 | 9 | 0 | | | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | - | 80 | 0 | 80 | 1 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 1 | 0 | 0 | 0 | @@ -482,13 +482,13 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 33 | 0 | 24 | 1 | | | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | - | 13 | 0 | 5 | 0 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 35 | 0 | 34 | 0 | -| | [@elastic/security-generative-ai](https://github.com/orgs/elastic/teams/security-generative-ai) | - | 174 | 0 | 147 | 9 | -| | [@elastic/security-generative-ai](https://github.com/orgs/elastic/teams/security-generative-ai) | - | 232 | 0 | 217 | 2 | +| | [@elastic/security-generative-ai](https://github.com/orgs/elastic/teams/security-generative-ai) | - | 165 | 0 | 138 | 9 | +| | [@elastic/security-generative-ai](https://github.com/orgs/elastic/teams/security-generative-ai) | - | 295 | 0 | 276 | 0 | | | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | - | 19 | 0 | 19 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 52 | 0 | 37 | 7 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 32 | 0 | 19 | 1 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 7 | 0 | 3 | 0 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 261 | 1 | 201 | 15 | +| | [@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-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 2 | 0 | 1 | 0 | | | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 63 | 1 | 63 | 6 | @@ -506,7 +506,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 1 | 0 | 0 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 1 | 0 | 1 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 26 | 0 | 26 | 1 | -| | [@elastic/platform-onboarding](https://github.com/orgs/elastic/teams/platform-onboarding) | - | 49 | 0 | 47 | 0 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 49 | 0 | 47 | 0 | | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | - | 33 | 3 | 24 | 6 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 3 | 0 | 3 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 1 | 0 | 1 | 0 | @@ -553,7 +553,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 12 | 0 | 0 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 152 | 1 | 0 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 141 | 0 | 5 | 0 | -| | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 48 | 0 | 0 | 0 | +| | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 50 | 0 | 0 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 11 | 0 | 0 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 36 | 4 | 8 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 12 | 0 | 1 | 0 | @@ -588,8 +588,8 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 1 | 0 | 0 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 1 | 0 | 1 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 1 | 0 | 1 | 0 | -| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 64 | 0 | 60 | 1 | -| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 194 | 0 | 163 | 5 | +| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 70 | 0 | 64 | 1 | +| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 202 | 0 | 167 | 5 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 168 | 0 | 55 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 13 | 0 | 7 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 22 | 0 | 9 | 0 | @@ -614,7 +614,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 13 | 0 | 11 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 113 | 0 | 107 | 2 | -| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 88 | 0 | 87 | 0 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 92 | 0 | 91 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | A component for creating resizable layouts containing a fixed width panel and a flexible panel, with support for horizontal and vertical layouts. | 18 | 0 | 5 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 13 | 2 | 8 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 5 | 0 | 5 | 1 | @@ -703,7 +703,6 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 8 | 0 | 8 | 4 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 16 | 0 | 6 | 0 | | | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 182 | 0 | 182 | 0 | -| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 6 | 0 | 6 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 6 | 0 | 6 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 20 | 0 | 12 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 4 | 0 | 4 | 0 | @@ -727,7 +726,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 | 149 | 0 | 80 | 2 | | | [@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 | 293 | 0 | 269 | 10 | +| | [@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 | 293 | 0 | 269 | 9 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 13 | 0 | 9 | 0 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 3 | 0 | 2 | 1 | | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | - | 81 | 1 | 21 | 2 | diff --git a/api_docs/presentation_panel.mdx b/api_docs/presentation_panel.mdx index 8c268e1f95f1b..0677c292ff609 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-05-20 +date: 2024-05-23 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 c3fbeb48c1cb4..6f2bd10ff875b 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-05-20 +date: 2024-05-23 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 24562df3c52b6..66d7afe58ebaa 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-05-20 +date: 2024-05-23 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 815446290093b..931b69b66de45 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-05-20 +date: 2024-05-23 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 8a9b064ae4b3e..9e775a6eca29f 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-05-20 +date: 2024-05-23 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 6640e4af8b91d..fb2afe7004da9 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-05-20 +date: 2024-05-23 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 7a0c154687213..ac1b2de1ad9f4 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'rollup'] --- import rollupObj from './rollup.devdocs.json'; diff --git a/api_docs/rule_registry.mdx b/api_docs/rule_registry.mdx index 08ce12e279590..49c28eada7f80 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-05-20 +date: 2024-05-23 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 fa58345d738ca..83726597df64f 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-05-20 +date: 2024-05-23 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 2bec6748e53cd..6eb20f85dbc3a 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-05-20 +date: 2024-05-23 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 5daf9853f828f..0e8eae7458730 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-05-20 +date: 2024-05-23 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 e228ca4121902..17bd462d431bc 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-05-20 +date: 2024-05-23 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 e97860955ca84..0ad496a993bac 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-05-20 +date: 2024-05-23 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 0d574769a21cd..a589b5a7ac6af 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-05-20 +date: 2024-05-23 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 16bc7de0b5688..d7148394389de 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-05-20 +date: 2024-05-23 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 2e07d5a49f159..5de2dea1e365b 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-05-20 +date: 2024-05-23 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 ae5c74157c1ba..b48113379f27f 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-05-20 +date: 2024-05-23 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 9a37ce5bc337b..3ffa95a41a432 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchConnectors'] --- import searchConnectorsObj from './search_connectors.devdocs.json'; diff --git a/api_docs/search_notebooks.mdx b/api_docs/search_notebooks.mdx index 4613c7395bbdc..113472e170f53 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-05-20 +date: 2024-05-23 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 018d2605b2f76..9679326cfaf07 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchPlayground'] --- import searchPlaygroundObj from './search_playground.devdocs.json'; diff --git a/api_docs/security.devdocs.json b/api_docs/security.devdocs.json index c86bad58007a3..6cb7517095a60 100644 --- a/api_docs/security.devdocs.json +++ b/api_docs/security.devdocs.json @@ -5038,7 +5038,7 @@ "label": "CreateAPIKeyParams", "description": [], "signature": [ - "Readonly<{ type?: \"rest\" | undefined; metadata?: Readonly<{} & {}> | undefined; expiration?: string | undefined; } & { name: string; role_descriptors: Record>; }> | Readonly<{ type?: \"rest\" | undefined; metadata?: Readonly<{} & {}> | undefined; expiration?: string | undefined; } & { name: string; kibana_role_descriptors: Record | undefined; } & { spaces: string[] | \"*\"[]; }>[]; elasticsearch: Readonly<{ cluster?: string[] | undefined; indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; }>[] | undefined; remote_cluster?: Readonly<{} & { privileges: string[]; clusters: string[]; }>[] | undefined; remote_indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; clusters: string[]; }>[] | undefined; run_as?: string[] | undefined; } & {}>; }>>; }> | Readonly<{ metadata?: Readonly<{} & {}> | undefined; expiration?: string | undefined; } & { type: \"cross_cluster\"; name: string; access: Readonly<{ search?: Readonly<{} & { names: string[]; }>[] | undefined; replication?: Readonly<{} & { names: string[]; }>[] | undefined; } & {}>; }>" + "Readonly<{ type?: \"rest\" | undefined; metadata?: Readonly<{} & {}> | undefined; expiration?: string | undefined; } & { name: string; role_descriptors: Record>; }> | Readonly<{ type?: \"rest\" | undefined; metadata?: Readonly<{} & {}> | undefined; expiration?: string | undefined; } & { name: string; kibana_role_descriptors: Record | undefined; } & { spaces: string[] | \"*\"[]; }>[]; elasticsearch: Readonly<{ cluster?: string[] | undefined; indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; }>[] | undefined; remote_cluster?: Readonly<{} & { privileges: string[]; clusters: string[]; }>[] | undefined; remote_indices?: Readonly<{ query?: string | undefined; field_security?: Record<\"grant\" | \"except\", string[]> | undefined; allow_restricted_indices?: boolean | undefined; } & { names: string[]; privileges: string[]; clusters: string[]; }>[] | undefined; run_as?: string[] | undefined; } & {}>; }>>; }> | Readonly<{ metadata?: Readonly<{} & {}> | undefined; expiration?: string | undefined; } & { type: \"cross_cluster\"; name: string; access: Readonly<{ search?: Readonly<{ query?: any; field_security?: any; allow_restricted_indices?: boolean | undefined; } & { names: string[]; }>[] | undefined; replication?: Readonly<{} & { names: string[]; }>[] | undefined; } & {}>; }>" ], "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", "deprecated": false, @@ -5070,7 +5070,7 @@ "label": "CreateCrossClusterAPIKeyParams", "description": [], "signature": [ - "{ readonly metadata?: Readonly<{} & {}> | undefined; readonly expiration?: string | undefined; readonly type: \"cross_cluster\"; readonly name: string; readonly access: Readonly<{ search?: Readonly<{} & { names: string[]; }>[] | undefined; replication?: Readonly<{} & { names: string[]; }>[] | undefined; } & {}>; }" + "{ readonly metadata?: Readonly<{} & {}> | undefined; readonly expiration?: string | undefined; readonly type: \"cross_cluster\"; readonly name: string; readonly access: Readonly<{ search?: Readonly<{ query?: any; field_security?: any; allow_restricted_indices?: boolean | undefined; } & { names: string[]; }>[] | undefined; replication?: Readonly<{} & { names: string[]; }>[] | undefined; } & {}>; }" ], "path": "x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts", "deprecated": false, diff --git a/api_docs/security.mdx b/api_docs/security.mdx index 493597afeb4da..5a3a571b9ca30 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-05-20 +date: 2024-05-23 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 4f10cc0529917..cc34ecefbd1a1 100644 --- a/api_docs/security_solution.devdocs.json +++ b/api_docs/security_solution.devdocs.json @@ -390,7 +390,7 @@ "label": "data", "description": [], "signature": [ - "({ id: string; type: \"eql\"; name: string; actions: { params: {} & { [k: string]: unknown; }; id: string; group: string; action_type_id: string; uuid?: string | undefined; alerts_filter?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; frequency?: { throttle: string | null; notifyWhen: \"onActionGroupChange\" | \"onActiveAlert\" | \"onThrottleInterval\"; summary: boolean; } | undefined; }[]; tags: string[]; setup: string; enabled: boolean; revision: number; query: string; interval: string; description: string; version: number; risk_score: number; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; from: string; to: string; language: \"eql\"; created_at: string; created_by: string; updated_at: string; updated_by: string; references: string[]; author: string[]; immutable: boolean; rule_id: string; threat: { framework: string; tactic: { id: string; name: string; reference: string; }; technique?: { id: string; name: string; reference: string; subtechnique?: { id: string; name: string; reference: string; }[] | undefined; }[] | undefined; }[]; risk_score_mapping: { value: string; field: string; operator: \"equals\"; risk_score?: number | undefined; }[]; severity_mapping: { value: string; field: string; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; operator: \"equals\"; }[]; exceptions_list: { id: string; type: \"endpoint\" | \"detection\" | \"rule_default\" | \"endpoint_trusted_apps\" | \"endpoint_events\" | \"endpoint_host_isolation_exceptions\" | \"endpoint_blocklists\"; list_id: string; namespace_type: \"single\" | \"agnostic\"; }[]; false_positives: string[]; max_signals: number; related_integrations: { version: string; package: string; integration?: string | undefined; }[]; required_fields: { type: string; name: string; ecs: boolean; }[]; namespace?: string | undefined; license?: string | undefined; throttle?: string | undefined; outcome?: \"exactMatch\" | \"aliasMatch\" | \"conflict\" | undefined; alias_target_id?: string | undefined; alias_purpose?: \"savedObjectConversion\" | \"savedObjectImport\" | undefined; meta?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; note?: string | undefined; rule_name_override?: string | undefined; timestamp_override?: string | undefined; timestamp_override_fallback_disabled?: boolean | undefined; timeline_id?: string | undefined; timeline_title?: string | undefined; building_block_type?: string | undefined; output_index?: string | undefined; investigation_fields?: { field_names: string[]; } | undefined; rule_source?: { type: \"external\"; is_customized: boolean; } | { type: \"internal\"; } | undefined; execution_summary?: { last_execution: { message: string; date: string; status: \"running\" | \"succeeded\" | \"failed\" | \"going to run\" | \"partial failure\"; metrics: { total_search_duration_ms?: number | undefined; total_indexing_duration_ms?: number | undefined; total_enrichment_duration_ms?: number | undefined; execution_gap_duration_s?: number | undefined; }; status_order: number; }; } | undefined; index?: string[] | undefined; data_view_id?: string | undefined; filters?: unknown[] | undefined; event_category_override?: string | undefined; tiebreaker_field?: string | undefined; timestamp_field?: string | undefined; alert_suppression?: { group_by: string[]; duration?: { value: number; unit: \"m\" | \"h\" | \"s\"; } | undefined; missing_fields_strategy?: \"doNotSuppress\" | \"suppress\" | undefined; } | undefined; } | { id: string; type: \"query\"; name: string; actions: { params: {} & { [k: string]: unknown; }; id: string; group: string; action_type_id: string; uuid?: string | undefined; alerts_filter?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; frequency?: { throttle: string | null; notifyWhen: \"onActionGroupChange\" | \"onActiveAlert\" | \"onThrottleInterval\"; summary: boolean; } | undefined; }[]; tags: string[]; setup: string; enabled: boolean; revision: number; query: string; interval: string; description: string; version: number; risk_score: number; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; from: string; to: string; language: \"kuery\" | \"lucene\"; created_at: string; created_by: string; updated_at: string; updated_by: string; references: string[]; author: string[]; immutable: boolean; rule_id: string; threat: { framework: string; tactic: { id: string; name: string; reference: string; }; technique?: { id: string; name: string; reference: string; subtechnique?: { id: string; name: string; reference: string; }[] | undefined; }[] | undefined; }[]; risk_score_mapping: { value: string; field: string; operator: \"equals\"; risk_score?: number | undefined; }[]; severity_mapping: { value: string; field: string; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; operator: \"equals\"; }[]; exceptions_list: { id: string; type: \"endpoint\" | \"detection\" | \"rule_default\" | \"endpoint_trusted_apps\" | \"endpoint_events\" | \"endpoint_host_isolation_exceptions\" | \"endpoint_blocklists\"; list_id: string; namespace_type: \"single\" | \"agnostic\"; }[]; false_positives: string[]; max_signals: number; related_integrations: { version: string; package: string; integration?: string | undefined; }[]; required_fields: { type: string; name: string; ecs: boolean; }[]; namespace?: string | undefined; license?: string | undefined; throttle?: string | undefined; outcome?: \"exactMatch\" | \"aliasMatch\" | \"conflict\" | undefined; alias_target_id?: string | undefined; alias_purpose?: \"savedObjectConversion\" | \"savedObjectImport\" | undefined; meta?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; note?: string | undefined; rule_name_override?: string | undefined; timestamp_override?: string | undefined; timestamp_override_fallback_disabled?: boolean | undefined; timeline_id?: string | undefined; timeline_title?: string | undefined; building_block_type?: string | undefined; output_index?: string | undefined; investigation_fields?: { field_names: string[]; } | undefined; rule_source?: { type: \"external\"; is_customized: boolean; } | { type: \"internal\"; } | undefined; execution_summary?: { last_execution: { message: string; date: string; status: \"running\" | \"succeeded\" | \"failed\" | \"going to run\" | \"partial failure\"; metrics: { total_search_duration_ms?: number | undefined; total_indexing_duration_ms?: number | undefined; total_enrichment_duration_ms?: number | undefined; execution_gap_duration_s?: number | undefined; }; status_order: number; }; } | undefined; index?: string[] | undefined; filters?: unknown[] | undefined; data_view_id?: string | undefined; alert_suppression?: { group_by: string[]; duration?: { value: number; unit: \"m\" | \"h\" | \"s\"; } | undefined; missing_fields_strategy?: \"doNotSuppress\" | \"suppress\" | undefined; } | undefined; saved_id?: string | undefined; response_actions?: ({ params: { query?: string | undefined; ecs_mapping?: Zod.objectOutputType<{}, Zod.ZodObject<{ field: Zod.ZodOptional; value: Zod.ZodOptional]>>; }, \"strip\", Zod.ZodTypeAny, { field?: string | undefined; value?: string | string[] | undefined; }, { field?: string | undefined; value?: string | string[] | undefined; }>, \"strip\"> | undefined; queries?: { id: string; query: string; ecs_mapping?: Zod.objectOutputType<{}, Zod.ZodObject<{ field: Zod.ZodOptional; value: Zod.ZodOptional]>>; }, \"strip\", Zod.ZodTypeAny, { field?: string | undefined; value?: string | string[] | undefined; }, { field?: string | undefined; value?: string | string[] | undefined; }>, \"strip\"> | undefined; version?: string | undefined; platform?: string | undefined; removed?: boolean | undefined; snapshot?: boolean | undefined; }[] | undefined; pack_id?: string | undefined; saved_query_id?: string | undefined; timeout?: number | undefined; }; action_type_id: \".osquery\"; } | { params: { command: \"isolate\"; comment?: string | undefined; } | { config: { field: string; overwrite: boolean; }; command: \"kill-process\" | \"suspend-process\"; comment?: string | undefined; }; action_type_id: \".endpoint\"; })[] | undefined; } | { id: string; type: \"saved_query\"; name: string; actions: { params: {} & { [k: string]: unknown; }; id: string; group: string; action_type_id: string; uuid?: string | undefined; alerts_filter?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; frequency?: { throttle: string | null; notifyWhen: \"onActionGroupChange\" | \"onActiveAlert\" | \"onThrottleInterval\"; summary: boolean; } | undefined; }[]; tags: string[]; setup: string; enabled: boolean; revision: number; interval: string; description: string; version: number; risk_score: number; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; from: string; to: string; language: \"kuery\" | \"lucene\"; created_at: string; created_by: string; updated_at: string; updated_by: string; references: string[]; author: string[]; immutable: boolean; rule_id: string; threat: { framework: string; tactic: { id: string; name: string; reference: string; }; technique?: { id: string; name: string; reference: string; subtechnique?: { id: string; name: string; reference: string; }[] | undefined; }[] | undefined; }[]; risk_score_mapping: { value: string; field: string; operator: \"equals\"; risk_score?: number | undefined; }[]; severity_mapping: { value: string; field: string; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; operator: \"equals\"; }[]; exceptions_list: { id: string; type: \"endpoint\" | \"detection\" | \"rule_default\" | \"endpoint_trusted_apps\" | \"endpoint_events\" | \"endpoint_host_isolation_exceptions\" | \"endpoint_blocklists\"; list_id: string; namespace_type: \"single\" | \"agnostic\"; }[]; false_positives: string[]; max_signals: number; related_integrations: { version: string; package: string; integration?: string | undefined; }[]; required_fields: { type: string; name: string; ecs: boolean; }[]; saved_id: string; namespace?: string | undefined; license?: string | undefined; throttle?: string | undefined; outcome?: \"exactMatch\" | \"aliasMatch\" | \"conflict\" | undefined; alias_target_id?: string | undefined; alias_purpose?: \"savedObjectConversion\" | \"savedObjectImport\" | undefined; meta?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; note?: string | undefined; rule_name_override?: string | undefined; timestamp_override?: string | undefined; timestamp_override_fallback_disabled?: boolean | undefined; timeline_id?: string | undefined; timeline_title?: string | undefined; building_block_type?: string | undefined; output_index?: string | undefined; investigation_fields?: { field_names: string[]; } | undefined; rule_source?: { type: \"external\"; is_customized: boolean; } | { type: \"internal\"; } | undefined; execution_summary?: { last_execution: { message: string; date: string; status: \"running\" | \"succeeded\" | \"failed\" | \"going to run\" | \"partial failure\"; metrics: { total_search_duration_ms?: number | undefined; total_indexing_duration_ms?: number | undefined; total_enrichment_duration_ms?: number | undefined; execution_gap_duration_s?: number | undefined; }; status_order: number; }; } | undefined; index?: string[] | undefined; query?: string | undefined; filters?: unknown[] | undefined; data_view_id?: string | undefined; alert_suppression?: { group_by: string[]; duration?: { value: number; unit: \"m\" | \"h\" | \"s\"; } | undefined; missing_fields_strategy?: \"doNotSuppress\" | \"suppress\" | undefined; } | undefined; response_actions?: ({ params: { query?: string | undefined; ecs_mapping?: Zod.objectOutputType<{}, Zod.ZodObject<{ field: Zod.ZodOptional; value: Zod.ZodOptional]>>; }, \"strip\", Zod.ZodTypeAny, { field?: string | undefined; value?: string | string[] | undefined; }, { field?: string | undefined; value?: string | string[] | undefined; }>, \"strip\"> | undefined; queries?: { id: string; query: string; ecs_mapping?: Zod.objectOutputType<{}, Zod.ZodObject<{ field: Zod.ZodOptional; value: Zod.ZodOptional]>>; }, \"strip\", Zod.ZodTypeAny, { field?: string | undefined; value?: string | string[] | undefined; }, { field?: string | undefined; value?: string | string[] | undefined; }>, \"strip\"> | undefined; version?: string | undefined; platform?: string | undefined; removed?: boolean | undefined; snapshot?: boolean | undefined; }[] | undefined; pack_id?: string | undefined; saved_query_id?: string | undefined; timeout?: number | undefined; }; action_type_id: \".osquery\"; } | { params: { command: \"isolate\"; comment?: string | undefined; } | { config: { field: string; overwrite: boolean; }; command: \"kill-process\" | \"suspend-process\"; comment?: string | undefined; }; action_type_id: \".endpoint\"; })[] | undefined; } | { id: string; type: \"threshold\"; name: string; actions: { params: {} & { [k: string]: unknown; }; id: string; group: string; action_type_id: string; uuid?: string | undefined; alerts_filter?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; frequency?: { throttle: string | null; notifyWhen: \"onActionGroupChange\" | \"onActiveAlert\" | \"onThrottleInterval\"; summary: boolean; } | undefined; }[]; tags: string[]; setup: string; enabled: boolean; revision: number; query: string; interval: string; description: string; version: number; risk_score: number; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; from: string; to: string; language: \"kuery\" | \"lucene\"; created_at: string; created_by: string; updated_at: string; updated_by: string; references: string[]; author: string[]; immutable: boolean; rule_id: string; threat: { framework: string; tactic: { id: string; name: string; reference: string; }; technique?: { id: string; name: string; reference: string; subtechnique?: { id: string; name: string; reference: string; }[] | undefined; }[] | undefined; }[]; risk_score_mapping: { value: string; field: string; operator: \"equals\"; risk_score?: number | undefined; }[]; severity_mapping: { value: string; field: string; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; operator: \"equals\"; }[]; exceptions_list: { id: string; type: \"endpoint\" | \"detection\" | \"rule_default\" | \"endpoint_trusted_apps\" | \"endpoint_events\" | \"endpoint_host_isolation_exceptions\" | \"endpoint_blocklists\"; list_id: string; namespace_type: \"single\" | \"agnostic\"; }[]; false_positives: string[]; max_signals: number; related_integrations: { version: string; package: string; integration?: string | undefined; }[]; required_fields: { type: string; name: string; ecs: boolean; }[]; threshold: { value: number; field: (string | string[]) & (string | string[] | undefined); cardinality?: { value: number; field: string; }[] | undefined; }; namespace?: string | undefined; license?: string | undefined; throttle?: string | undefined; outcome?: \"exactMatch\" | \"aliasMatch\" | \"conflict\" | undefined; alias_target_id?: string | undefined; alias_purpose?: \"savedObjectConversion\" | \"savedObjectImport\" | undefined; meta?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; note?: string | undefined; rule_name_override?: string | undefined; timestamp_override?: string | undefined; timestamp_override_fallback_disabled?: boolean | undefined; timeline_id?: string | undefined; timeline_title?: string | undefined; building_block_type?: string | undefined; output_index?: string | undefined; investigation_fields?: { field_names: string[]; } | undefined; rule_source?: { type: \"external\"; is_customized: boolean; } | { type: \"internal\"; } | undefined; execution_summary?: { last_execution: { message: string; date: string; status: \"running\" | \"succeeded\" | \"failed\" | \"going to run\" | \"partial failure\"; metrics: { total_search_duration_ms?: number | undefined; total_indexing_duration_ms?: number | undefined; total_enrichment_duration_ms?: number | undefined; execution_gap_duration_s?: number | undefined; }; status_order: number; }; } | undefined; index?: string[] | undefined; filters?: unknown[] | undefined; data_view_id?: string | undefined; alert_suppression?: { duration: { value: number; unit: \"m\" | \"h\" | \"s\"; }; } | undefined; saved_id?: string | undefined; } | { id: string; type: \"threat_match\"; name: string; actions: { params: {} & { [k: string]: unknown; }; id: string; group: string; action_type_id: string; uuid?: string | undefined; alerts_filter?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; frequency?: { throttle: string | null; notifyWhen: \"onActionGroupChange\" | \"onActiveAlert\" | \"onThrottleInterval\"; summary: boolean; } | undefined; }[]; tags: string[]; setup: string; enabled: boolean; revision: number; query: string; interval: string; description: string; version: number; risk_score: number; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; from: string; to: string; language: \"kuery\" | \"lucene\"; created_at: string; created_by: string; updated_at: string; updated_by: string; references: string[]; author: string[]; immutable: boolean; rule_id: string; threat: { framework: string; tactic: { id: string; name: string; reference: string; }; technique?: { id: string; name: string; reference: string; subtechnique?: { id: string; name: string; reference: string; }[] | undefined; }[] | undefined; }[]; risk_score_mapping: { value: string; field: string; operator: \"equals\"; risk_score?: number | undefined; }[]; severity_mapping: { value: string; field: string; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; operator: \"equals\"; }[]; exceptions_list: { id: string; type: \"endpoint\" | \"detection\" | \"rule_default\" | \"endpoint_trusted_apps\" | \"endpoint_events\" | \"endpoint_host_isolation_exceptions\" | \"endpoint_blocklists\"; list_id: string; namespace_type: \"single\" | \"agnostic\"; }[]; false_positives: string[]; max_signals: number; related_integrations: { version: string; package: string; integration?: string | undefined; }[]; required_fields: { type: string; name: string; ecs: boolean; }[]; threat_query: string; threat_mapping: { entries: { value: string; type: \"mapping\"; field: string; }[]; }[]; threat_index: string[]; namespace?: string | undefined; license?: string | undefined; throttle?: string | undefined; outcome?: \"exactMatch\" | \"aliasMatch\" | \"conflict\" | undefined; alias_target_id?: string | undefined; alias_purpose?: \"savedObjectConversion\" | \"savedObjectImport\" | undefined; meta?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; note?: string | undefined; rule_name_override?: string | undefined; timestamp_override?: string | undefined; timestamp_override_fallback_disabled?: boolean | undefined; timeline_id?: string | undefined; timeline_title?: string | undefined; building_block_type?: string | undefined; output_index?: string | undefined; investigation_fields?: { field_names: string[]; } | undefined; rule_source?: { type: \"external\"; is_customized: boolean; } | { type: \"internal\"; } | undefined; execution_summary?: { last_execution: { message: string; date: string; status: \"running\" | \"succeeded\" | \"failed\" | \"going to run\" | \"partial failure\"; metrics: { total_search_duration_ms?: number | undefined; total_indexing_duration_ms?: number | undefined; total_enrichment_duration_ms?: number | undefined; execution_gap_duration_s?: number | undefined; }; status_order: number; }; } | undefined; index?: string[] | undefined; filters?: unknown[] | undefined; data_view_id?: string | undefined; alert_suppression?: { group_by: string[]; duration?: { value: number; unit: \"m\" | \"h\" | \"s\"; } | undefined; missing_fields_strategy?: \"doNotSuppress\" | \"suppress\" | undefined; } | undefined; saved_id?: string | undefined; threat_filters?: unknown[] | undefined; threat_indicator_path?: string | undefined; threat_language?: \"lucene\" | \"kuery\" | undefined; concurrent_searches?: number | undefined; items_per_search?: number | undefined; } | { id: string; type: \"machine_learning\"; name: string; actions: { params: {} & { [k: string]: unknown; }; id: string; group: string; action_type_id: string; uuid?: string | undefined; alerts_filter?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; frequency?: { throttle: string | null; notifyWhen: \"onActionGroupChange\" | \"onActiveAlert\" | \"onThrottleInterval\"; summary: boolean; } | undefined; }[]; tags: string[]; setup: string; enabled: boolean; revision: number; interval: string; description: string; version: number; risk_score: number; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; from: string; to: string; created_at: string; created_by: string; updated_at: string; updated_by: string; references: string[]; author: string[]; immutable: boolean; rule_id: string; threat: { framework: string; tactic: { id: string; name: string; reference: string; }; technique?: { id: string; name: string; reference: string; subtechnique?: { id: string; name: string; reference: string; }[] | undefined; }[] | undefined; }[]; risk_score_mapping: { value: string; field: string; operator: \"equals\"; risk_score?: number | undefined; }[]; severity_mapping: { value: string; field: string; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; operator: \"equals\"; }[]; exceptions_list: { id: string; type: \"endpoint\" | \"detection\" | \"rule_default\" | \"endpoint_trusted_apps\" | \"endpoint_events\" | \"endpoint_host_isolation_exceptions\" | \"endpoint_blocklists\"; list_id: string; namespace_type: \"single\" | \"agnostic\"; }[]; false_positives: string[]; max_signals: number; related_integrations: { version: string; package: string; integration?: string | undefined; }[]; required_fields: { type: string; name: string; ecs: boolean; }[]; anomaly_threshold: number; machine_learning_job_id: (string | string[]) & (string | string[] | undefined); namespace?: string | undefined; license?: string | undefined; throttle?: string | undefined; outcome?: \"exactMatch\" | \"aliasMatch\" | \"conflict\" | undefined; alias_target_id?: string | undefined; alias_purpose?: \"savedObjectConversion\" | \"savedObjectImport\" | undefined; meta?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; note?: string | undefined; rule_name_override?: string | undefined; timestamp_override?: string | undefined; timestamp_override_fallback_disabled?: boolean | undefined; timeline_id?: string | undefined; timeline_title?: string | undefined; building_block_type?: string | undefined; output_index?: string | undefined; investigation_fields?: { field_names: string[]; } | undefined; rule_source?: { type: \"external\"; is_customized: boolean; } | { type: \"internal\"; } | undefined; execution_summary?: { last_execution: { message: string; date: string; status: \"running\" | \"succeeded\" | \"failed\" | \"going to run\" | \"partial failure\"; metrics: { total_search_duration_ms?: number | undefined; total_indexing_duration_ms?: number | undefined; total_enrichment_duration_ms?: number | undefined; execution_gap_duration_s?: number | undefined; }; status_order: number; }; } | undefined; } | { id: string; type: \"new_terms\"; name: string; actions: { params: {} & { [k: string]: unknown; }; id: string; group: string; action_type_id: string; uuid?: string | undefined; alerts_filter?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; frequency?: { throttle: string | null; notifyWhen: \"onActionGroupChange\" | \"onActiveAlert\" | \"onThrottleInterval\"; summary: boolean; } | undefined; }[]; tags: string[]; setup: string; enabled: boolean; revision: number; query: string; interval: string; description: string; version: number; risk_score: number; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; from: string; to: string; language: \"kuery\" | \"lucene\"; created_at: string; created_by: string; updated_at: string; updated_by: string; references: string[]; author: string[]; immutable: boolean; rule_id: string; threat: { framework: string; tactic: { id: string; name: string; reference: string; }; technique?: { id: string; name: string; reference: string; subtechnique?: { id: string; name: string; reference: string; }[] | undefined; }[] | undefined; }[]; risk_score_mapping: { value: string; field: string; operator: \"equals\"; risk_score?: number | undefined; }[]; severity_mapping: { value: string; field: string; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; operator: \"equals\"; }[]; exceptions_list: { id: string; type: \"endpoint\" | \"detection\" | \"rule_default\" | \"endpoint_trusted_apps\" | \"endpoint_events\" | \"endpoint_host_isolation_exceptions\" | \"endpoint_blocklists\"; list_id: string; namespace_type: \"single\" | \"agnostic\"; }[]; false_positives: string[]; max_signals: number; related_integrations: { version: string; package: string; integration?: string | undefined; }[]; required_fields: { type: string; name: string; ecs: boolean; }[]; new_terms_fields: string[]; history_window_start: string; namespace?: string | undefined; license?: string | undefined; throttle?: string | undefined; outcome?: \"exactMatch\" | \"aliasMatch\" | \"conflict\" | undefined; alias_target_id?: string | undefined; alias_purpose?: \"savedObjectConversion\" | \"savedObjectImport\" | undefined; meta?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; note?: string | undefined; rule_name_override?: string | undefined; timestamp_override?: string | undefined; timestamp_override_fallback_disabled?: boolean | undefined; timeline_id?: string | undefined; timeline_title?: string | undefined; building_block_type?: string | undefined; output_index?: string | undefined; investigation_fields?: { field_names: string[]; } | undefined; rule_source?: { type: \"external\"; is_customized: boolean; } | { type: \"internal\"; } | undefined; execution_summary?: { last_execution: { message: string; date: string; status: \"running\" | \"succeeded\" | \"failed\" | \"going to run\" | \"partial failure\"; metrics: { total_search_duration_ms?: number | undefined; total_indexing_duration_ms?: number | undefined; total_enrichment_duration_ms?: number | undefined; execution_gap_duration_s?: number | undefined; }; status_order: number; }; } | undefined; index?: string[] | undefined; filters?: unknown[] | undefined; data_view_id?: string | undefined; alert_suppression?: { group_by: string[]; duration?: { value: number; unit: \"m\" | \"h\" | \"s\"; } | undefined; missing_fields_strategy?: \"doNotSuppress\" | \"suppress\" | undefined; } | undefined; } | { id: string; type: \"esql\"; name: string; actions: { params: {} & { [k: string]: unknown; }; id: string; group: string; action_type_id: string; uuid?: string | undefined; alerts_filter?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; frequency?: { throttle: string | null; notifyWhen: \"onActionGroupChange\" | \"onActiveAlert\" | \"onThrottleInterval\"; summary: boolean; } | undefined; }[]; tags: string[]; setup: string; enabled: boolean; revision: number; query: string; interval: string; description: string; version: number; risk_score: number; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; from: string; to: string; language: \"esql\"; created_at: string; created_by: string; updated_at: string; updated_by: string; references: string[]; author: string[]; immutable: boolean; rule_id: string; threat: { framework: string; tactic: { id: string; name: string; reference: string; }; technique?: { id: string; name: string; reference: string; subtechnique?: { id: string; name: string; reference: string; }[] | undefined; }[] | undefined; }[]; risk_score_mapping: { value: string; field: string; operator: \"equals\"; risk_score?: number | undefined; }[]; severity_mapping: { value: string; field: string; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; operator: \"equals\"; }[]; exceptions_list: { id: string; type: \"endpoint\" | \"detection\" | \"rule_default\" | \"endpoint_trusted_apps\" | \"endpoint_events\" | \"endpoint_host_isolation_exceptions\" | \"endpoint_blocklists\"; list_id: string; namespace_type: \"single\" | \"agnostic\"; }[]; false_positives: string[]; max_signals: number; related_integrations: { version: string; package: string; integration?: string | undefined; }[]; required_fields: { type: string; name: string; ecs: boolean; }[]; namespace?: string | undefined; license?: string | undefined; throttle?: string | undefined; outcome?: \"exactMatch\" | \"aliasMatch\" | \"conflict\" | undefined; alias_target_id?: string | undefined; alias_purpose?: \"savedObjectConversion\" | \"savedObjectImport\" | undefined; meta?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; note?: string | undefined; rule_name_override?: string | undefined; timestamp_override?: string | undefined; timestamp_override_fallback_disabled?: boolean | undefined; timeline_id?: string | undefined; timeline_title?: string | undefined; building_block_type?: string | undefined; output_index?: string | undefined; investigation_fields?: { field_names: string[]; } | undefined; rule_source?: { type: \"external\"; is_customized: boolean; } | { type: \"internal\"; } | undefined; execution_summary?: { last_execution: { message: string; date: string; status: \"running\" | \"succeeded\" | \"failed\" | \"going to run\" | \"partial failure\"; metrics: { total_search_duration_ms?: number | undefined; total_indexing_duration_ms?: number | undefined; total_enrichment_duration_ms?: number | undefined; execution_gap_duration_s?: number | undefined; }; status_order: number; }; } | undefined; })[]" + "({ id: string; type: \"eql\"; name: string; actions: { params: {} & { [k: string]: unknown; }; id: string; group: string; action_type_id: string; uuid?: string | undefined; alerts_filter?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; frequency?: { throttle: string | null; notifyWhen: \"onActionGroupChange\" | \"onActiveAlert\" | \"onThrottleInterval\"; summary: boolean; } | undefined; }[]; tags: string[]; setup: string; enabled: boolean; revision: number; query: string; interval: string; description: string; version: number; risk_score: number; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; from: string; to: string; language: \"eql\"; created_at: string; created_by: string; updated_at: string; updated_by: string; references: string[]; author: string[]; immutable: boolean; rule_id: string; threat: { framework: string; tactic: { id: string; name: string; reference: string; }; technique?: { id: string; name: string; reference: string; subtechnique?: { id: string; name: string; reference: string; }[] | undefined; }[] | undefined; }[]; risk_score_mapping: { value: string; field: string; operator: \"equals\"; risk_score?: number | undefined; }[]; severity_mapping: { value: string; field: string; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; operator: \"equals\"; }[]; exceptions_list: { id: string; type: \"endpoint\" | \"detection\" | \"rule_default\" | \"endpoint_trusted_apps\" | \"endpoint_events\" | \"endpoint_host_isolation_exceptions\" | \"endpoint_blocklists\"; list_id: string; namespace_type: \"single\" | \"agnostic\"; }[]; false_positives: string[]; max_signals: number; related_integrations: { version: string; package: string; integration?: string | undefined; }[]; required_fields: { type: string; name: string; ecs: boolean; }[]; namespace?: string | undefined; license?: string | undefined; throttle?: string | undefined; outcome?: \"exactMatch\" | \"aliasMatch\" | \"conflict\" | undefined; alias_target_id?: string | undefined; alias_purpose?: \"savedObjectConversion\" | \"savedObjectImport\" | undefined; meta?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; note?: string | undefined; rule_name_override?: string | undefined; timestamp_override?: string | undefined; timestamp_override_fallback_disabled?: boolean | undefined; timeline_id?: string | undefined; timeline_title?: string | undefined; building_block_type?: string | undefined; output_index?: string | undefined; investigation_fields?: { field_names: string[]; } | undefined; rule_source?: { type: \"external\"; is_customized: boolean; } | { type: \"internal\"; } | undefined; execution_summary?: { last_execution: { message: string; date: string; status: \"running\" | \"succeeded\" | \"failed\" | \"going to run\" | \"partial failure\"; metrics: { total_search_duration_ms?: number | undefined; total_indexing_duration_ms?: number | undefined; total_enrichment_duration_ms?: number | undefined; execution_gap_duration_s?: number | undefined; }; status_order: number; }; } | undefined; index?: string[] | undefined; data_view_id?: string | undefined; filters?: unknown[] | undefined; event_category_override?: string | undefined; tiebreaker_field?: string | undefined; timestamp_field?: string | undefined; alert_suppression?: { group_by: string[]; duration?: { value: number; unit: \"m\" | \"h\" | \"s\"; } | undefined; missing_fields_strategy?: \"doNotSuppress\" | \"suppress\" | undefined; } | undefined; } | { id: string; type: \"query\"; name: string; actions: { params: {} & { [k: string]: unknown; }; id: string; group: string; action_type_id: string; uuid?: string | undefined; alerts_filter?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; frequency?: { throttle: string | null; notifyWhen: \"onActionGroupChange\" | \"onActiveAlert\" | \"onThrottleInterval\"; summary: boolean; } | undefined; }[]; tags: string[]; setup: string; enabled: boolean; revision: number; query: string; interval: string; description: string; version: number; risk_score: number; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; from: string; to: string; language: \"kuery\" | \"lucene\"; created_at: string; created_by: string; updated_at: string; updated_by: string; references: string[]; author: string[]; immutable: boolean; rule_id: string; threat: { framework: string; tactic: { id: string; name: string; reference: string; }; technique?: { id: string; name: string; reference: string; subtechnique?: { id: string; name: string; reference: string; }[] | undefined; }[] | undefined; }[]; risk_score_mapping: { value: string; field: string; operator: \"equals\"; risk_score?: number | undefined; }[]; severity_mapping: { value: string; field: string; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; operator: \"equals\"; }[]; exceptions_list: { id: string; type: \"endpoint\" | \"detection\" | \"rule_default\" | \"endpoint_trusted_apps\" | \"endpoint_events\" | \"endpoint_host_isolation_exceptions\" | \"endpoint_blocklists\"; list_id: string; namespace_type: \"single\" | \"agnostic\"; }[]; false_positives: string[]; max_signals: number; related_integrations: { version: string; package: string; integration?: string | undefined; }[]; required_fields: { type: string; name: string; ecs: boolean; }[]; namespace?: string | undefined; license?: string | undefined; throttle?: string | undefined; outcome?: \"exactMatch\" | \"aliasMatch\" | \"conflict\" | undefined; alias_target_id?: string | undefined; alias_purpose?: \"savedObjectConversion\" | \"savedObjectImport\" | undefined; meta?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; note?: string | undefined; rule_name_override?: string | undefined; timestamp_override?: string | undefined; timestamp_override_fallback_disabled?: boolean | undefined; timeline_id?: string | undefined; timeline_title?: string | undefined; building_block_type?: string | undefined; output_index?: string | undefined; investigation_fields?: { field_names: string[]; } | undefined; rule_source?: { type: \"external\"; is_customized: boolean; } | { type: \"internal\"; } | undefined; execution_summary?: { last_execution: { message: string; date: string; status: \"running\" | \"succeeded\" | \"failed\" | \"going to run\" | \"partial failure\"; metrics: { total_search_duration_ms?: number | undefined; total_indexing_duration_ms?: number | undefined; total_enrichment_duration_ms?: number | undefined; execution_gap_duration_s?: number | undefined; }; status_order: number; }; } | undefined; index?: string[] | undefined; filters?: unknown[] | undefined; data_view_id?: string | undefined; alert_suppression?: { group_by: string[]; duration?: { value: number; unit: \"m\" | \"h\" | \"s\"; } | undefined; missing_fields_strategy?: \"doNotSuppress\" | \"suppress\" | undefined; } | undefined; saved_id?: string | undefined; response_actions?: ({ params: { query?: string | undefined; ecs_mapping?: Zod.objectOutputType<{}, Zod.ZodObject<{ field: Zod.ZodOptional; value: Zod.ZodOptional]>>; }, \"strip\", Zod.ZodTypeAny, { field?: string | undefined; value?: string | string[] | undefined; }, { field?: string | undefined; value?: string | string[] | undefined; }>, \"strip\"> | undefined; queries?: { id: string; query: string; ecs_mapping?: Zod.objectOutputType<{}, Zod.ZodObject<{ field: Zod.ZodOptional; value: Zod.ZodOptional]>>; }, \"strip\", Zod.ZodTypeAny, { field?: string | undefined; value?: string | string[] | undefined; }, { field?: string | undefined; value?: string | string[] | undefined; }>, \"strip\"> | undefined; version?: string | undefined; platform?: string | undefined; removed?: boolean | undefined; snapshot?: boolean | undefined; }[] | undefined; pack_id?: string | undefined; saved_query_id?: string | undefined; timeout?: number | undefined; }; action_type_id: \".osquery\"; } | { params: { command: \"isolate\"; comment?: string | undefined; } | { config: { field: string; overwrite: boolean; }; command: \"kill-process\" | \"suspend-process\"; comment?: string | undefined; }; action_type_id: \".endpoint\"; })[] | undefined; } | { id: string; type: \"saved_query\"; name: string; actions: { params: {} & { [k: string]: unknown; }; id: string; group: string; action_type_id: string; uuid?: string | undefined; alerts_filter?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; frequency?: { throttle: string | null; notifyWhen: \"onActionGroupChange\" | \"onActiveAlert\" | \"onThrottleInterval\"; summary: boolean; } | undefined; }[]; tags: string[]; setup: string; enabled: boolean; revision: number; interval: string; description: string; version: number; risk_score: number; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; from: string; to: string; language: \"kuery\" | \"lucene\"; created_at: string; created_by: string; updated_at: string; updated_by: string; references: string[]; author: string[]; immutable: boolean; rule_id: string; threat: { framework: string; tactic: { id: string; name: string; reference: string; }; technique?: { id: string; name: string; reference: string; subtechnique?: { id: string; name: string; reference: string; }[] | undefined; }[] | undefined; }[]; risk_score_mapping: { value: string; field: string; operator: \"equals\"; risk_score?: number | undefined; }[]; severity_mapping: { value: string; field: string; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; operator: \"equals\"; }[]; exceptions_list: { id: string; type: \"endpoint\" | \"detection\" | \"rule_default\" | \"endpoint_trusted_apps\" | \"endpoint_events\" | \"endpoint_host_isolation_exceptions\" | \"endpoint_blocklists\"; list_id: string; namespace_type: \"single\" | \"agnostic\"; }[]; false_positives: string[]; max_signals: number; related_integrations: { version: string; package: string; integration?: string | undefined; }[]; required_fields: { type: string; name: string; ecs: boolean; }[]; saved_id: string; namespace?: string | undefined; license?: string | undefined; throttle?: string | undefined; outcome?: \"exactMatch\" | \"aliasMatch\" | \"conflict\" | undefined; alias_target_id?: string | undefined; alias_purpose?: \"savedObjectConversion\" | \"savedObjectImport\" | undefined; meta?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; note?: string | undefined; rule_name_override?: string | undefined; timestamp_override?: string | undefined; timestamp_override_fallback_disabled?: boolean | undefined; timeline_id?: string | undefined; timeline_title?: string | undefined; building_block_type?: string | undefined; output_index?: string | undefined; investigation_fields?: { field_names: string[]; } | undefined; rule_source?: { type: \"external\"; is_customized: boolean; } | { type: \"internal\"; } | undefined; execution_summary?: { last_execution: { message: string; date: string; status: \"running\" | \"succeeded\" | \"failed\" | \"going to run\" | \"partial failure\"; metrics: { total_search_duration_ms?: number | undefined; total_indexing_duration_ms?: number | undefined; total_enrichment_duration_ms?: number | undefined; execution_gap_duration_s?: number | undefined; }; status_order: number; }; } | undefined; index?: string[] | undefined; query?: string | undefined; filters?: unknown[] | undefined; data_view_id?: string | undefined; alert_suppression?: { group_by: string[]; duration?: { value: number; unit: \"m\" | \"h\" | \"s\"; } | undefined; missing_fields_strategy?: \"doNotSuppress\" | \"suppress\" | undefined; } | undefined; response_actions?: ({ params: { query?: string | undefined; ecs_mapping?: Zod.objectOutputType<{}, Zod.ZodObject<{ field: Zod.ZodOptional; value: Zod.ZodOptional]>>; }, \"strip\", Zod.ZodTypeAny, { field?: string | undefined; value?: string | string[] | undefined; }, { field?: string | undefined; value?: string | string[] | undefined; }>, \"strip\"> | undefined; queries?: { id: string; query: string; ecs_mapping?: Zod.objectOutputType<{}, Zod.ZodObject<{ field: Zod.ZodOptional; value: Zod.ZodOptional]>>; }, \"strip\", Zod.ZodTypeAny, { field?: string | undefined; value?: string | string[] | undefined; }, { field?: string | undefined; value?: string | string[] | undefined; }>, \"strip\"> | undefined; version?: string | undefined; platform?: string | undefined; removed?: boolean | undefined; snapshot?: boolean | undefined; }[] | undefined; pack_id?: string | undefined; saved_query_id?: string | undefined; timeout?: number | undefined; }; action_type_id: \".osquery\"; } | { params: { command: \"isolate\"; comment?: string | undefined; } | { config: { field: string; overwrite: boolean; }; command: \"kill-process\" | \"suspend-process\"; comment?: string | undefined; }; action_type_id: \".endpoint\"; })[] | undefined; } | { id: string; type: \"threshold\"; name: string; actions: { params: {} & { [k: string]: unknown; }; id: string; group: string; action_type_id: string; uuid?: string | undefined; alerts_filter?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; frequency?: { throttle: string | null; notifyWhen: \"onActionGroupChange\" | \"onActiveAlert\" | \"onThrottleInterval\"; summary: boolean; } | undefined; }[]; tags: string[]; setup: string; enabled: boolean; revision: number; query: string; interval: string; description: string; version: number; risk_score: number; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; from: string; to: string; language: \"kuery\" | \"lucene\"; created_at: string; created_by: string; updated_at: string; updated_by: string; references: string[]; author: string[]; immutable: boolean; rule_id: string; threat: { framework: string; tactic: { id: string; name: string; reference: string; }; technique?: { id: string; name: string; reference: string; subtechnique?: { id: string; name: string; reference: string; }[] | undefined; }[] | undefined; }[]; risk_score_mapping: { value: string; field: string; operator: \"equals\"; risk_score?: number | undefined; }[]; severity_mapping: { value: string; field: string; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; operator: \"equals\"; }[]; exceptions_list: { id: string; type: \"endpoint\" | \"detection\" | \"rule_default\" | \"endpoint_trusted_apps\" | \"endpoint_events\" | \"endpoint_host_isolation_exceptions\" | \"endpoint_blocklists\"; list_id: string; namespace_type: \"single\" | \"agnostic\"; }[]; false_positives: string[]; max_signals: number; related_integrations: { version: string; package: string; integration?: string | undefined; }[]; required_fields: { type: string; name: string; ecs: boolean; }[]; threshold: { value: number; field: (string | string[]) & (string | string[] | undefined); cardinality?: { value: number; field: string; }[] | undefined; }; namespace?: string | undefined; license?: string | undefined; throttle?: string | undefined; outcome?: \"exactMatch\" | \"aliasMatch\" | \"conflict\" | undefined; alias_target_id?: string | undefined; alias_purpose?: \"savedObjectConversion\" | \"savedObjectImport\" | undefined; meta?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; note?: string | undefined; rule_name_override?: string | undefined; timestamp_override?: string | undefined; timestamp_override_fallback_disabled?: boolean | undefined; timeline_id?: string | undefined; timeline_title?: string | undefined; building_block_type?: string | undefined; output_index?: string | undefined; investigation_fields?: { field_names: string[]; } | undefined; rule_source?: { type: \"external\"; is_customized: boolean; } | { type: \"internal\"; } | undefined; execution_summary?: { last_execution: { message: string; date: string; status: \"running\" | \"succeeded\" | \"failed\" | \"going to run\" | \"partial failure\"; metrics: { total_search_duration_ms?: number | undefined; total_indexing_duration_ms?: number | undefined; total_enrichment_duration_ms?: number | undefined; execution_gap_duration_s?: number | undefined; }; status_order: number; }; } | undefined; index?: string[] | undefined; filters?: unknown[] | undefined; data_view_id?: string | undefined; alert_suppression?: { duration: { value: number; unit: \"m\" | \"h\" | \"s\"; }; } | undefined; saved_id?: string | undefined; } | { id: string; type: \"threat_match\"; name: string; actions: { params: {} & { [k: string]: unknown; }; id: string; group: string; action_type_id: string; uuid?: string | undefined; alerts_filter?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; frequency?: { throttle: string | null; notifyWhen: \"onActionGroupChange\" | \"onActiveAlert\" | \"onThrottleInterval\"; summary: boolean; } | undefined; }[]; tags: string[]; setup: string; enabled: boolean; revision: number; query: string; interval: string; description: string; version: number; risk_score: number; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; from: string; to: string; language: \"kuery\" | \"lucene\"; created_at: string; created_by: string; updated_at: string; updated_by: string; references: string[]; author: string[]; immutable: boolean; rule_id: string; threat: { framework: string; tactic: { id: string; name: string; reference: string; }; technique?: { id: string; name: string; reference: string; subtechnique?: { id: string; name: string; reference: string; }[] | undefined; }[] | undefined; }[]; risk_score_mapping: { value: string; field: string; operator: \"equals\"; risk_score?: number | undefined; }[]; severity_mapping: { value: string; field: string; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; operator: \"equals\"; }[]; exceptions_list: { id: string; type: \"endpoint\" | \"detection\" | \"rule_default\" | \"endpoint_trusted_apps\" | \"endpoint_events\" | \"endpoint_host_isolation_exceptions\" | \"endpoint_blocklists\"; list_id: string; namespace_type: \"single\" | \"agnostic\"; }[]; false_positives: string[]; max_signals: number; related_integrations: { version: string; package: string; integration?: string | undefined; }[]; required_fields: { type: string; name: string; ecs: boolean; }[]; threat_query: string; threat_mapping: { entries: { value: string; type: \"mapping\"; field: string; }[]; }[]; threat_index: string[]; namespace?: string | undefined; license?: string | undefined; throttle?: string | undefined; outcome?: \"exactMatch\" | \"aliasMatch\" | \"conflict\" | undefined; alias_target_id?: string | undefined; alias_purpose?: \"savedObjectConversion\" | \"savedObjectImport\" | undefined; meta?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; note?: string | undefined; rule_name_override?: string | undefined; timestamp_override?: string | undefined; timestamp_override_fallback_disabled?: boolean | undefined; timeline_id?: string | undefined; timeline_title?: string | undefined; building_block_type?: string | undefined; output_index?: string | undefined; investigation_fields?: { field_names: string[]; } | undefined; rule_source?: { type: \"external\"; is_customized: boolean; } | { type: \"internal\"; } | undefined; execution_summary?: { last_execution: { message: string; date: string; status: \"running\" | \"succeeded\" | \"failed\" | \"going to run\" | \"partial failure\"; metrics: { total_search_duration_ms?: number | undefined; total_indexing_duration_ms?: number | undefined; total_enrichment_duration_ms?: number | undefined; execution_gap_duration_s?: number | undefined; }; status_order: number; }; } | undefined; index?: string[] | undefined; filters?: unknown[] | undefined; data_view_id?: string | undefined; alert_suppression?: { group_by: string[]; duration?: { value: number; unit: \"m\" | \"h\" | \"s\"; } | undefined; missing_fields_strategy?: \"doNotSuppress\" | \"suppress\" | undefined; } | undefined; saved_id?: string | undefined; threat_filters?: unknown[] | undefined; threat_indicator_path?: string | undefined; threat_language?: \"lucene\" | \"kuery\" | undefined; concurrent_searches?: number | undefined; items_per_search?: number | undefined; } | { id: string; type: \"machine_learning\"; name: string; actions: { params: {} & { [k: string]: unknown; }; id: string; group: string; action_type_id: string; uuid?: string | undefined; alerts_filter?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; frequency?: { throttle: string | null; notifyWhen: \"onActionGroupChange\" | \"onActiveAlert\" | \"onThrottleInterval\"; summary: boolean; } | undefined; }[]; tags: string[]; setup: string; enabled: boolean; revision: number; interval: string; description: string; version: number; risk_score: number; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; from: string; to: string; created_at: string; created_by: string; updated_at: string; updated_by: string; references: string[]; author: string[]; immutable: boolean; rule_id: string; threat: { framework: string; tactic: { id: string; name: string; reference: string; }; technique?: { id: string; name: string; reference: string; subtechnique?: { id: string; name: string; reference: string; }[] | undefined; }[] | undefined; }[]; risk_score_mapping: { value: string; field: string; operator: \"equals\"; risk_score?: number | undefined; }[]; severity_mapping: { value: string; field: string; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; operator: \"equals\"; }[]; exceptions_list: { id: string; type: \"endpoint\" | \"detection\" | \"rule_default\" | \"endpoint_trusted_apps\" | \"endpoint_events\" | \"endpoint_host_isolation_exceptions\" | \"endpoint_blocklists\"; list_id: string; namespace_type: \"single\" | \"agnostic\"; }[]; false_positives: string[]; max_signals: number; related_integrations: { version: string; package: string; integration?: string | undefined; }[]; required_fields: { type: string; name: string; ecs: boolean; }[]; anomaly_threshold: number; machine_learning_job_id: (string | string[]) & (string | string[] | undefined); namespace?: string | undefined; license?: string | undefined; throttle?: string | undefined; outcome?: \"exactMatch\" | \"aliasMatch\" | \"conflict\" | undefined; alias_target_id?: string | undefined; alias_purpose?: \"savedObjectConversion\" | \"savedObjectImport\" | undefined; meta?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; note?: string | undefined; rule_name_override?: string | undefined; timestamp_override?: string | undefined; timestamp_override_fallback_disabled?: boolean | undefined; timeline_id?: string | undefined; timeline_title?: string | undefined; building_block_type?: string | undefined; output_index?: string | undefined; investigation_fields?: { field_names: string[]; } | undefined; rule_source?: { type: \"external\"; is_customized: boolean; } | { type: \"internal\"; } | undefined; execution_summary?: { last_execution: { message: string; date: string; status: \"running\" | \"succeeded\" | \"failed\" | \"going to run\" | \"partial failure\"; metrics: { total_search_duration_ms?: number | undefined; total_indexing_duration_ms?: number | undefined; total_enrichment_duration_ms?: number | undefined; execution_gap_duration_s?: number | undefined; }; status_order: number; }; } | undefined; } | { id: string; type: \"new_terms\"; name: string; actions: { params: {} & { [k: string]: unknown; }; id: string; group: string; action_type_id: string; uuid?: string | undefined; alerts_filter?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; frequency?: { throttle: string | null; notifyWhen: \"onActionGroupChange\" | \"onActiveAlert\" | \"onThrottleInterval\"; summary: boolean; } | undefined; }[]; tags: string[]; setup: string; enabled: boolean; revision: number; query: string; interval: string; description: string; version: number; risk_score: number; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; from: string; to: string; language: \"kuery\" | \"lucene\"; created_at: string; created_by: string; updated_at: string; updated_by: string; references: string[]; author: string[]; immutable: boolean; rule_id: string; threat: { framework: string; tactic: { id: string; name: string; reference: string; }; technique?: { id: string; name: string; reference: string; subtechnique?: { id: string; name: string; reference: string; }[] | undefined; }[] | undefined; }[]; risk_score_mapping: { value: string; field: string; operator: \"equals\"; risk_score?: number | undefined; }[]; severity_mapping: { value: string; field: string; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; operator: \"equals\"; }[]; exceptions_list: { id: string; type: \"endpoint\" | \"detection\" | \"rule_default\" | \"endpoint_trusted_apps\" | \"endpoint_events\" | \"endpoint_host_isolation_exceptions\" | \"endpoint_blocklists\"; list_id: string; namespace_type: \"single\" | \"agnostic\"; }[]; false_positives: string[]; max_signals: number; related_integrations: { version: string; package: string; integration?: string | undefined; }[]; required_fields: { type: string; name: string; ecs: boolean; }[]; new_terms_fields: string[]; history_window_start: string; namespace?: string | undefined; license?: string | undefined; throttle?: string | undefined; outcome?: \"exactMatch\" | \"aliasMatch\" | \"conflict\" | undefined; alias_target_id?: string | undefined; alias_purpose?: \"savedObjectConversion\" | \"savedObjectImport\" | undefined; meta?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; note?: string | undefined; rule_name_override?: string | undefined; timestamp_override?: string | undefined; timestamp_override_fallback_disabled?: boolean | undefined; timeline_id?: string | undefined; timeline_title?: string | undefined; building_block_type?: string | undefined; output_index?: string | undefined; investigation_fields?: { field_names: string[]; } | undefined; rule_source?: { type: \"external\"; is_customized: boolean; } | { type: \"internal\"; } | undefined; execution_summary?: { last_execution: { message: string; date: string; status: \"running\" | \"succeeded\" | \"failed\" | \"going to run\" | \"partial failure\"; metrics: { total_search_duration_ms?: number | undefined; total_indexing_duration_ms?: number | undefined; total_enrichment_duration_ms?: number | undefined; execution_gap_duration_s?: number | undefined; }; status_order: number; }; } | undefined; index?: string[] | undefined; filters?: unknown[] | undefined; data_view_id?: string | undefined; alert_suppression?: { group_by: string[]; duration?: { value: number; unit: \"m\" | \"h\" | \"s\"; } | undefined; missing_fields_strategy?: \"doNotSuppress\" | \"suppress\" | undefined; } | undefined; } | { id: string; type: \"esql\"; name: string; actions: { params: {} & { [k: string]: unknown; }; id: string; group: string; action_type_id: string; uuid?: string | undefined; alerts_filter?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; frequency?: { throttle: string | null; notifyWhen: \"onActionGroupChange\" | \"onActiveAlert\" | \"onThrottleInterval\"; summary: boolean; } | undefined; }[]; tags: string[]; setup: string; enabled: boolean; revision: number; query: string; interval: string; description: string; version: number; risk_score: number; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; from: string; to: string; language: \"esql\"; created_at: string; created_by: string; updated_at: string; updated_by: string; references: string[]; author: string[]; immutable: boolean; rule_id: string; threat: { framework: string; tactic: { id: string; name: string; reference: string; }; technique?: { id: string; name: string; reference: string; subtechnique?: { id: string; name: string; reference: string; }[] | undefined; }[] | undefined; }[]; risk_score_mapping: { value: string; field: string; operator: \"equals\"; risk_score?: number | undefined; }[]; severity_mapping: { value: string; field: string; severity: \"medium\" | \"high\" | \"low\" | \"critical\"; operator: \"equals\"; }[]; exceptions_list: { id: string; type: \"endpoint\" | \"detection\" | \"rule_default\" | \"endpoint_trusted_apps\" | \"endpoint_events\" | \"endpoint_host_isolation_exceptions\" | \"endpoint_blocklists\"; list_id: string; namespace_type: \"single\" | \"agnostic\"; }[]; false_positives: string[]; max_signals: number; related_integrations: { version: string; package: string; integration?: string | undefined; }[]; required_fields: { type: string; name: string; ecs: boolean; }[]; namespace?: string | undefined; license?: string | undefined; throttle?: string | undefined; outcome?: \"exactMatch\" | \"aliasMatch\" | \"conflict\" | undefined; alias_target_id?: string | undefined; alias_purpose?: \"savedObjectConversion\" | \"savedObjectImport\" | undefined; meta?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; note?: string | undefined; rule_name_override?: string | undefined; timestamp_override?: string | undefined; timestamp_override_fallback_disabled?: boolean | undefined; timeline_id?: string | undefined; timeline_title?: string | undefined; building_block_type?: string | undefined; output_index?: string | undefined; investigation_fields?: { field_names: string[]; } | undefined; rule_source?: { type: \"external\"; is_customized: boolean; } | { type: \"internal\"; } | undefined; execution_summary?: { last_execution: { message: string; date: string; status: \"running\" | \"succeeded\" | \"failed\" | \"going to run\" | \"partial failure\"; metrics: { total_search_duration_ms?: number | undefined; total_indexing_duration_ms?: number | undefined; total_enrichment_duration_ms?: number | undefined; execution_gap_duration_s?: number | undefined; }; status_order: number; }; } | undefined; alert_suppression?: { group_by: string[]; duration?: { value: number; unit: \"m\" | \"h\" | \"s\"; } | undefined; missing_fields_strategy?: \"doNotSuppress\" | \"suppress\" | undefined; } | undefined; })[]" ], "path": "x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/types.ts", "deprecated": false, @@ -485,7 +485,7 @@ "\nExperimental flag needed to enable the link" ], "signature": [ - "\"assistantModelEvaluation\" | \"tGridEnabled\" | \"tGridEventRenderedViewEnabled\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"insightsRelatedAlertsByProcessAncestry\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionsEnabled\" | \"endpointResponseActionsEnabled\" | \"responseActionUploadEnabled\" | \"automatedProcessActionsEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"responseActionsSentinelOneV2Enabled\" | \"responseActionsSentinelOneGetFileEnabled\" | \"agentStatusClientEnabled\" | \"responseActionsCrowdstrikeManualHostIsolationEnabled\" | \"alertsPageChartsEnabled\" | \"alertTypeEnabled\" | \"expandableFlyoutInCreateRuleEnabled\" | \"expandableEventFlyoutEnabled\" | \"expandableTimelineFlyoutEnabled\" | \"alertsPageFiltersEnabled\" | \"newUserDetailsFlyout\" | \"newUserDetailsFlyoutManagedUser\" | \"newHostDetailsFlyout\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | \"riskEnginePrivilegesRouteEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"crowdstrikeDataInAnalyzerEnabled\" | \"jamfDataInAnalyzerEnabled\" | \"jsonPrebuiltRulesDiffingEnabled\" | \"timelineEsqlTabDisabled\" | \"unifiedComponentsInTimelineEnabled\" | \"analyzerDatePickersAndSourcererDisabled\" | \"perFieldPrebuiltRulesDiffingEnabled\" | \"malwareOnWriteScanOptionAvailable\" | \"unifiedManifestEnabled\" | \"aiAssistantFlyoutMode\" | \"valueListItemsModalEnabled\" | \"bulkCustomHighlightedFieldsEnabled\" | undefined" + "\"assistantKnowledgeBaseByDefault\" | \"assistantModelEvaluation\" | \"tGridEnabled\" | \"tGridEventRenderedViewEnabled\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"insightsRelatedAlertsByProcessAncestry\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionsEnabled\" | \"endpointResponseActionsEnabled\" | \"responseActionUploadEnabled\" | \"automatedProcessActionsEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"responseActionsSentinelOneV2Enabled\" | \"responseActionsSentinelOneGetFileEnabled\" | \"agentStatusClientEnabled\" | \"responseActionsCrowdstrikeManualHostIsolationEnabled\" | \"responseActionScanEnabled\" | \"alertsPageChartsEnabled\" | \"alertTypeEnabled\" | \"expandableFlyoutInCreateRuleEnabled\" | \"expandableEventFlyoutEnabled\" | \"expandableTimelineFlyoutEnabled\" | \"alertsPageFiltersEnabled\" | \"newUserDetailsFlyout\" | \"newUserDetailsFlyoutManagedUser\" | \"newHostDetailsFlyout\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | \"alertSuppressionForEsqlRuleEnabled\" | \"riskEnginePrivilegesRouteEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"crowdstrikeDataInAnalyzerEnabled\" | \"jamfDataInAnalyzerEnabled\" | \"jsonPrebuiltRulesDiffingEnabled\" | \"timelineEsqlTabDisabled\" | \"unifiedComponentsInTimelineEnabled\" | \"analyzerDatePickersAndSourcererDisabled\" | \"perFieldPrebuiltRulesDiffingEnabled\" | \"malwareOnWriteScanOptionAvailable\" | \"unifiedManifestEnabled\" | \"aiAssistantFlyoutMode\" | \"valueListItemsModalEnabled\" | \"bulkCustomHighlightedFieldsEnabled\" | 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": [ - "\"assistantModelEvaluation\" | \"tGridEnabled\" | \"tGridEventRenderedViewEnabled\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"insightsRelatedAlertsByProcessAncestry\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionsEnabled\" | \"endpointResponseActionsEnabled\" | \"responseActionUploadEnabled\" | \"automatedProcessActionsEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"responseActionsSentinelOneV2Enabled\" | \"responseActionsSentinelOneGetFileEnabled\" | \"agentStatusClientEnabled\" | \"responseActionsCrowdstrikeManualHostIsolationEnabled\" | \"alertsPageChartsEnabled\" | \"alertTypeEnabled\" | \"expandableFlyoutInCreateRuleEnabled\" | \"expandableEventFlyoutEnabled\" | \"expandableTimelineFlyoutEnabled\" | \"alertsPageFiltersEnabled\" | \"newUserDetailsFlyout\" | \"newUserDetailsFlyoutManagedUser\" | \"newHostDetailsFlyout\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | \"riskEnginePrivilegesRouteEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"crowdstrikeDataInAnalyzerEnabled\" | \"jamfDataInAnalyzerEnabled\" | \"jsonPrebuiltRulesDiffingEnabled\" | \"timelineEsqlTabDisabled\" | \"unifiedComponentsInTimelineEnabled\" | \"analyzerDatePickersAndSourcererDisabled\" | \"perFieldPrebuiltRulesDiffingEnabled\" | \"malwareOnWriteScanOptionAvailable\" | \"unifiedManifestEnabled\" | \"aiAssistantFlyoutMode\" | \"valueListItemsModalEnabled\" | \"bulkCustomHighlightedFieldsEnabled\" | undefined" + "\"assistantKnowledgeBaseByDefault\" | \"assistantModelEvaluation\" | \"tGridEnabled\" | \"tGridEventRenderedViewEnabled\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"insightsRelatedAlertsByProcessAncestry\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionsEnabled\" | \"endpointResponseActionsEnabled\" | \"responseActionUploadEnabled\" | \"automatedProcessActionsEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"responseActionsSentinelOneV2Enabled\" | \"responseActionsSentinelOneGetFileEnabled\" | \"agentStatusClientEnabled\" | \"responseActionsCrowdstrikeManualHostIsolationEnabled\" | \"responseActionScanEnabled\" | \"alertsPageChartsEnabled\" | \"alertTypeEnabled\" | \"expandableFlyoutInCreateRuleEnabled\" | \"expandableEventFlyoutEnabled\" | \"expandableTimelineFlyoutEnabled\" | \"alertsPageFiltersEnabled\" | \"newUserDetailsFlyout\" | \"newUserDetailsFlyoutManagedUser\" | \"newHostDetailsFlyout\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | \"alertSuppressionForEsqlRuleEnabled\" | \"riskEnginePrivilegesRouteEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"crowdstrikeDataInAnalyzerEnabled\" | \"jamfDataInAnalyzerEnabled\" | \"jsonPrebuiltRulesDiffingEnabled\" | \"timelineEsqlTabDisabled\" | \"unifiedComponentsInTimelineEnabled\" | \"analyzerDatePickersAndSourcererDisabled\" | \"perFieldPrebuiltRulesDiffingEnabled\" | \"malwareOnWriteScanOptionAvailable\" | \"unifiedManifestEnabled\" | \"aiAssistantFlyoutMode\" | \"valueListItemsModalEnabled\" | \"bulkCustomHighlightedFieldsEnabled\" | undefined" ], "path": "x-pack/plugins/security_solution/public/common/links/types.ts", "deprecated": false, @@ -1964,7 +1964,7 @@ "label": "experimentalFeatures", "description": [], "signature": [ - "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: 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 agentStatusClientEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutInCreateRuleEnabled: boolean; readonly expandableEventFlyoutEnabled: boolean; readonly expandableTimelineFlyoutEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly newHostDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly unifiedComponentsInTimelineEnabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly perFieldPrebuiltRulesDiffingEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly aiAssistantFlyoutMode: boolean; readonly valueListItemsModalEnabled: boolean; readonly bulkCustomHighlightedFieldsEnabled: boolean; }" + "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: 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 agentStatusClientEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly responseActionScanEnabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutInCreateRuleEnabled: boolean; readonly expandableEventFlyoutEnabled: boolean; readonly expandableTimelineFlyoutEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly newUserDetailsFlyout: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly newHostDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly alertSuppressionForEsqlRuleEnabled: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly unifiedComponentsInTimelineEnabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly perFieldPrebuiltRulesDiffingEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly aiAssistantFlyoutMode: boolean; readonly valueListItemsModalEnabled: boolean; readonly bulkCustomHighlightedFieldsEnabled: boolean; }" ], "path": "x-pack/plugins/security_solution/public/types.ts", "deprecated": false, @@ -3054,7 +3054,7 @@ "\nThe security solution generic experimental features" ], "signature": [ - "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: 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 agentStatusClientEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutInCreateRuleEnabled: boolean; readonly expandableEventFlyoutEnabled: boolean; readonly expandableTimelineFlyoutEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly newHostDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly unifiedComponentsInTimelineEnabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly perFieldPrebuiltRulesDiffingEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly aiAssistantFlyoutMode: boolean; readonly valueListItemsModalEnabled: boolean; readonly bulkCustomHighlightedFieldsEnabled: boolean; }" + "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: 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 agentStatusClientEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly responseActionScanEnabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutInCreateRuleEnabled: boolean; readonly expandableEventFlyoutEnabled: boolean; readonly expandableTimelineFlyoutEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly newUserDetailsFlyout: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly newHostDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly alertSuppressionForEsqlRuleEnabled: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly unifiedComponentsInTimelineEnabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly perFieldPrebuiltRulesDiffingEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly aiAssistantFlyoutMode: boolean; readonly valueListItemsModalEnabled: boolean; readonly bulkCustomHighlightedFieldsEnabled: boolean; }" ], "path": "x-pack/plugins/security_solution/server/plugin_contract.ts", "deprecated": false, @@ -3230,7 +3230,7 @@ "label": "ExperimentalFeatures", "description": [], "signature": [ - "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: 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 agentStatusClientEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutInCreateRuleEnabled: boolean; readonly expandableEventFlyoutEnabled: boolean; readonly expandableTimelineFlyoutEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly newHostDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly unifiedComponentsInTimelineEnabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly perFieldPrebuiltRulesDiffingEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly aiAssistantFlyoutMode: boolean; readonly valueListItemsModalEnabled: boolean; readonly bulkCustomHighlightedFieldsEnabled: boolean; }" + "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: 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 agentStatusClientEnabled: boolean; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: boolean; readonly responseActionScanEnabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutInCreateRuleEnabled: boolean; readonly expandableEventFlyoutEnabled: boolean; readonly expandableTimelineFlyoutEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly assistantKnowledgeBaseByDefault: boolean; readonly newUserDetailsFlyout: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly newHostDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly alertSuppressionForEsqlRuleEnabled: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly crowdstrikeDataInAnalyzerEnabled: boolean; readonly jamfDataInAnalyzerEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; readonly unifiedComponentsInTimelineEnabled: boolean; readonly analyzerDatePickersAndSourcererDisabled: boolean; readonly perFieldPrebuiltRulesDiffingEnabled: boolean; readonly malwareOnWriteScanOptionAvailable: boolean; readonly unifiedManifestEnabled: boolean; readonly aiAssistantFlyoutMode: boolean; readonly valueListItemsModalEnabled: boolean; readonly bulkCustomHighlightedFieldsEnabled: boolean; }" ], "path": "x-pack/plugins/security_solution/common/experimental_features.ts", "deprecated": false, @@ -3296,7 +3296,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 tGridEnabled: true; readonly tGridEventRenderedViewEnabled: true; readonly excludePoliciesInFilterEnabled: false; readonly kubernetesEnabled: true; readonly donutChartEmbeddablesEnabled: false; readonly previewTelemetryUrlEnabled: false; readonly insightsRelatedAlertsByProcessAncestry: true; readonly extendedRuleExecutionLoggingEnabled: false; readonly socTrendsEnabled: false; readonly responseActionsEnabled: true; readonly endpointResponseActionsEnabled: true; readonly responseActionUploadEnabled: true; readonly automatedProcessActionsEnabled: true; readonly responseActionsSentinelOneV1Enabled: true; readonly responseActionsSentinelOneV2Enabled: false; readonly responseActionsSentinelOneGetFileEnabled: false; readonly agentStatusClientEnabled: false; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: false; readonly alertsPageChartsEnabled: true; readonly alertTypeEnabled: false; readonly expandableFlyoutInCreateRuleEnabled: true; readonly expandableEventFlyoutEnabled: true; readonly expandableTimelineFlyoutEnabled: true; readonly alertsPageFiltersEnabled: true; readonly assistantModelEvaluation: false; readonly newUserDetailsFlyout: true; readonly newUserDetailsFlyoutManagedUser: false; readonly newHostDetailsFlyout: true; readonly riskScoringPersistence: true; readonly riskScoringRoutesEnabled: true; readonly esqlRulesDisabled: false; readonly protectionUpdatesEnabled: true; readonly disableTimelineSaveTour: false; readonly riskEnginePrivilegesRouteEnabled: true; readonly sentinelOneDataInAnalyzerEnabled: true; readonly sentinelOneManualHostActionsEnabled: true; readonly crowdstrikeDataInAnalyzerEnabled: false; readonly jamfDataInAnalyzerEnabled: false; readonly jsonPrebuiltRulesDiffingEnabled: true; readonly timelineEsqlTabDisabled: false; readonly unifiedComponentsInTimelineEnabled: false; readonly analyzerDatePickersAndSourcererDisabled: false; readonly perFieldPrebuiltRulesDiffingEnabled: true; readonly malwareOnWriteScanOptionAvailable: true; readonly unifiedManifestEnabled: false; readonly aiAssistantFlyoutMode: true; readonly valueListItemsModalEnabled: true; readonly bulkCustomHighlightedFieldsEnabled: false; }" + "{ readonly tGridEnabled: true; readonly tGridEventRenderedViewEnabled: true; readonly excludePoliciesInFilterEnabled: false; readonly kubernetesEnabled: true; readonly donutChartEmbeddablesEnabled: false; readonly previewTelemetryUrlEnabled: false; readonly insightsRelatedAlertsByProcessAncestry: true; 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: false; readonly agentStatusClientEnabled: false; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: false; readonly responseActionScanEnabled: false; readonly alertsPageChartsEnabled: true; readonly alertTypeEnabled: false; readonly expandableFlyoutInCreateRuleEnabled: true; readonly expandableEventFlyoutEnabled: true; readonly expandableTimelineFlyoutEnabled: true; readonly alertsPageFiltersEnabled: true; readonly assistantModelEvaluation: false; readonly assistantKnowledgeBaseByDefault: false; readonly newUserDetailsFlyout: true; readonly newUserDetailsFlyoutManagedUser: false; readonly newHostDetailsFlyout: true; readonly riskScoringPersistence: true; readonly riskScoringRoutesEnabled: true; readonly esqlRulesDisabled: false; readonly protectionUpdatesEnabled: true; readonly disableTimelineSaveTour: false; readonly alertSuppressionForEsqlRuleEnabled: false; readonly riskEnginePrivilegesRouteEnabled: true; readonly sentinelOneDataInAnalyzerEnabled: true; readonly sentinelOneManualHostActionsEnabled: true; readonly crowdstrikeDataInAnalyzerEnabled: false; readonly jamfDataInAnalyzerEnabled: false; readonly jsonPrebuiltRulesDiffingEnabled: true; readonly timelineEsqlTabDisabled: false; readonly unifiedComponentsInTimelineEnabled: false; readonly analyzerDatePickersAndSourcererDisabled: false; readonly perFieldPrebuiltRulesDiffingEnabled: true; readonly malwareOnWriteScanOptionAvailable: true; readonly unifiedManifestEnabled: false; readonly aiAssistantFlyoutMode: true; readonly valueListItemsModalEnabled: true; readonly bulkCustomHighlightedFieldsEnabled: 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 27007122fc6d8..a4dd2fe91910d 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-05-20 +date: 2024-05-23 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 811a8cda4699f..7b83d52c4877d 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-05-20 +date: 2024-05-23 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 cc23b3a3c1587..c5e81174f913f 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-05-20 +date: 2024-05-23 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 c0af522c9791d..3ff31a505cfee 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-05-20 +date: 2024-05-23 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 d81adb6537e73..3805435240f60 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-05-20 +date: 2024-05-23 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 61c74b672b4e7..58dc7abc6babe 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-05-20 +date: 2024-05-23 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 ea83468fcd1d3..cbdb227a5bbd6 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-05-20 +date: 2024-05-23 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 8e94973d5c349..a91d0f55c4f24 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-05-20 +date: 2024-05-23 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 02cfed22cb843..e4abe45387191 100644 --- a/api_docs/slo.devdocs.json +++ b/api_docs/slo.devdocs.json @@ -446,7 +446,13 @@ "label": "aiops", "description": [], "signature": [ - "AiopsPluginStart" + { + "pluginId": "aiops", + "scope": "public", + "docId": "kibAiopsPluginApi", + "section": "def-public.AiopsPluginStart", + "text": "AiopsPluginStart" + } ], "path": "x-pack/plugins/observability_solution/slo/public/types.ts", "deprecated": false, diff --git a/api_docs/slo.mdx b/api_docs/slo.mdx index 7ef4a611abcf8..351bf0d55eabf 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-05-20 +date: 2024-05-23 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 0ea1d3172dd3b..998acac3af752 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-05-20 +date: 2024-05-23 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 087542719d1e4..c23563d6f81a5 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-05-20 +date: 2024-05-23 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 1a2bbb0524a15..3c87b2c63c469 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-05-20 +date: 2024-05-23 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 33fc2ffd33a4e..7ebd1550adb27 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'stackConnectors'] --- import stackConnectorsObj from './stack_connectors.devdocs.json'; diff --git a/api_docs/task_manager.mdx b/api_docs/task_manager.mdx index 6e2fc9a19eaf8..278e6ddcc7200 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'taskManager'] --- import taskManagerObj from './task_manager.devdocs.json'; diff --git a/api_docs/telemetry.mdx b/api_docs/telemetry.mdx index 79de411a6e575..9aefcbf3ac7e9 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-05-20 +date: 2024-05-23 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 95d3eec19eba4..768268f4908b3 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-05-20 +date: 2024-05-23 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 ec85be98e62b7..bd9a51e17f0f7 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-05-20 +date: 2024-05-23 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 6531727d0d0fc..66cdaf73d16a3 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryManagementSection'] --- import telemetryManagementSectionObj from './telemetry_management_section.devdocs.json'; diff --git a/api_docs/text_based_languages.mdx b/api_docs/text_based_languages.mdx index e5df0709fea7d..bf0515086de0a 100644 --- a/api_docs/text_based_languages.mdx +++ b/api_docs/text_based_languages.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/textBasedLanguages title: "textBasedLanguages" image: https://source.unsplash.com/400x175/?github description: API docs for the textBasedLanguages plugin -date: 2024-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'textBasedLanguages'] --- import textBasedLanguagesObj from './text_based_languages.devdocs.json'; diff --git a/api_docs/threat_intelligence.mdx b/api_docs/threat_intelligence.mdx index 8a58fa683984b..db02a7f0c0d31 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-05-20 +date: 2024-05-23 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 207e867788d38..446052635f118 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-05-20 +date: 2024-05-23 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 77864ff7ffdb3..d3489abbf6e11 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'transform'] --- import transformObj from './transform.devdocs.json'; diff --git a/api_docs/triggers_actions_ui.mdx b/api_docs/triggers_actions_ui.mdx index ecceb395dcf5d..aba3f9b8934e8 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-05-20 +date: 2024-05-23 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 b561d2da43a8e..f88d78cb1ebe8 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-05-20 +date: 2024-05-23 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 7522b26b6f3f5..476ccf4c1d5bd 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-05-20 +date: 2024-05-23 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 c1f174a432bb2..51be22e31a540 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-05-20 +date: 2024-05-23 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 074ba92429cbe..ee8f8db46d5a1 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-05-20 +date: 2024-05-23 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 0ef774e7bf6be..ef3058893f1e1 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-05-20 +date: 2024-05-23 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 b79b3c80e18e6..493b2f2a6e299 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-05-20 +date: 2024-05-23 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 db3a5756af139..380fe2499e750 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-05-20 +date: 2024-05-23 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 d7b26a682cb27..b979a58e3f595 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-05-20 +date: 2024-05-23 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 e741e98b12d20..4e4e5989012fc 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-05-20 +date: 2024-05-23 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 5bca97e899953..8d07b17b8fac0 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-05-20 +date: 2024-05-23 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 193e96d59bb23..1cb48316e34dc 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-05-20 +date: 2024-05-23 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 7d5ef7ea92dff..ba01696036162 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-05-20 +date: 2024-05-23 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 dab1277709244..b183bb9b893ec 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-05-20 +date: 2024-05-23 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 496bb0951f15c..e3db11b5ca947 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-05-20 +date: 2024-05-23 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 9bb57b81870b0..15841c296b934 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-05-20 +date: 2024-05-23 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 0607b3fbe497e..369f8f5195301 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-05-20 +date: 2024-05-23 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 0ff4a1b9f893a..d6afbb4f65880 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-05-20 +date: 2024-05-23 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 ebc6df00a2798..130dfd61ec60a 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-05-20 +date: 2024-05-23 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 be3ee2bb95a9b..f871b7437fd7a 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-05-20 +date: 2024-05-23 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 b120e745b9875..2909da04a3e77 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-05-20 +date: 2024-05-23 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 4c015585d1a70..093b2029669f4 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-05-20 +date: 2024-05-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizations'] --- import visualizationsObj from './visualizations.devdocs.json'; diff --git a/config/serverless.oblt.yml b/config/serverless.oblt.yml index c9d7f7c1f992f..7d15e2f5673e9 100644 --- a/config/serverless.oblt.yml +++ b/config/serverless.oblt.yml @@ -53,6 +53,7 @@ xpack.fleet.internal.registry.excludePackages: [ # Security integrations 'endpoint', 'beaconing', + 'security_detection_engine', # Removed in 8.11 integrations 'cisco', diff --git a/docs/CHANGELOG.asciidoc b/docs/CHANGELOG.asciidoc index 09b083b7213b2..5cb979389a4d2 100644 --- a/docs/CHANGELOG.asciidoc +++ b/docs/CHANGELOG.asciidoc @@ -10,6 +10,7 @@ Review important information about the {kib} 8.x releases. +* <> * <> * <> * <> @@ -65,6 +66,316 @@ Review important information about the {kib} 8.x releases. * <> -- +[[release-notes-8.14.0]] +== {kib} 8.14.0 + +For information about the {kib} 8.14.0 release, review the following information. + +[float] +[[breaking-changes-8.14.0]] +=== Breaking changes + +Breaking changes can prevent your application from optimal operation and performance. +Before you upgrade to 8.14.0, review the breaking changes, then mitigate the impact to your application. + +[discrete] +[[breaking-182074]] +.Renamed an advanced setting to enable {esql}. +[%collapsible] +==== +*Details* + +The advanced setting which hides {esql} from the UI has been renamed from `discover:enableESQL` to `enableESQL`. It is enabled by default and must be switched off to disable {esql} features from your {kib} applications. For more information, refer to ({kibana-pull}182074[#182074]). +==== + +[discrete] +[[breaking-178879]] +.The unified search filter builder is Generally Available. +[%collapsible] +==== +*Details* + +The unified search filter builder (OR / AND) is out of technical preview. For more information, refer to ({kibana-pull}178879[#178879]). +==== + +[discrete] +[[breaking-178860]] +.{esql} is Generally Available. +[%collapsible] +==== +*Details* + +{esql} comes out of technical preview and is generally available. For more information, refer to ({kibana-pull}178860[#178860]). +==== + +[discrete] +[[breaking-177549]] +.The region map visualization type is Generally Available in Lens. +[%collapsible] +==== +*Details* + +The visualization type, region map, comes out of technical preview and is generally available. For more information, refer to ({kibana-pull}177549[#177549]). +==== + +[discrete] +[[breaking-177089]] +.UI enhancements to managed tags. +[%collapsible] +==== +*Details* + +UI improvements for managed tags. For more information, refer to ({kibana-pull}177089[#177089]). +==== + +[float] +[[features-8.14.0]] +=== Features +{kib} 8.14.0 adds the following new and notable features. + +Alerting:: +* Adds a warning when changing the index pattern while at least one rule relies on the current one ({kibana-pull}180310[#180310]). +* Enrich the alert flyout with a new overview tab ({kibana-pull}178863[#178863]). +* Adds history chart for multiple conditions ({kibana-pull}180578[#180578]). +* Implements a tabbed design for existing alert detail pages ({kibana-pull}179529[#179529]). +* Stops reporting no data alert for missing groups that are untracked ({kibana-pull}179512[#179512]). +* Adds a new modal window that lets users interact with value lists directly ({kibana-pull}179339[#179339]). +* Adds new rule type selection modal ({kibana-pull}179285[#179285]). +* Enables filters for the alert search bar on the Observability Alerts page ({kibana-pull}178886[#178886]). +APM:: +* Adds a new API to support linking APM from the Profiling UI ({kibana-pull}180677[#180677]). +* Enables fast filter on Service inventory ({kibana-pull}179096[#179096]). +Cases:: +* Adds automatically creating cases when an alert is triggered ({kibana-pull}168369[#168369]). +* Adds "Additional Fields" field to the Jira action form UI ({kibana-pull}179262[#179262]). +Dashboards:: +* Adds logic and UI improvements where invalid controls selections are no longer ignored, improving the overall loading speed of a dashboard ({kibana-pull}174201[#174201]). +Discover:: +* Allows storing a configured {esql} visualization ({kibana-pull}175227[#175227]). +* Adds document comparison mode ({kibana-pull}166577[#166577]). +Elastic Security:: +For the Elastic Security 8.14.0 release information, refer to {security-guide}/release-notes.html[_Elastic Security Solution Release Notes_]. +ES|QL:: +* Adds a query history component which displays the 20 most recent queries ({kibana-pull}178302[#178302]). +Fleet:: +* Adds subfeatures privileges for Fleet, for Agents, Agent policies and Settings, this feature is in technical preview ({kibana-pull}179889[#179889]). +* Implements state machine behavior for package install ({kibana-pull}178657[#178657]). +* Lowers the default `total_fields` limit to 1000 from 10k ({kibana-pull}178398[#178398]). +* Avoids subobject and scalar mapping conflicts by setting `subobjects: false` on custom integrations ({kibana-pull}178397[#178397]). +* Adds functionality to `default_fields` field, so a query can run against all fields in the mapping ({kibana-pull}178020[#178020]). +* Relaxes delete restrictions for managed content installed by Fleet ({kibana-pull}179113[#179113]). +Infrastructure:: +* Adds a dashboard tab in the UI to the asset details view ({kibana-pull}178518[#178518]). +Lens & Visualizations:: +* Replaces `expression_gauge` from `Goal` to `Bullet` in *Lens* ({kibana-pull}177766[#177766]). +Machine Learning:: +* Removes the technical preview badge for pattern analysis ({kibana-pull}181020[#181020]). +* Adds query history for the {esql} Data visualizer ({kibana-pull}179098[#179098]). +Management:: +* {kib} now uses Elasticsearch's `_async_search/status/{id}` endpoint (instead of `_async_search/{id}`) when polling on search requests to improve performance.({kibana-pull}178921[#178921]). +Observability:: +* The timeslice SLOs calculation for the SLI value now includes the no data slices as good slices. For existing "Timeslice" SLOs you will need to use the `POST /api/observability/slos/{slo.id}/_reset` endpoint to reset the transforms to take advantage of the new calculation ({kibana-pull}181888[#181888]). +* Adds support for user instructions via Knowledge base or API request ({kibana-pull}180263[#180263]). +* Adds baseline alert detail pages ({kibana-pull}180256[#180256]). +* Adds a new connector that can call the AI assistant ({kibana-pull}179980[#179980]). +* Adds a link to Discover to view good/bad events in the event panel ({kibana-pull}178008[#178008]). +* Adds customization for Virtual Columns in Field List ({kibana-pull}177626[#177626]). +* Adds dependencies for Burn Rate rule suppression ({kibana-pull}177078[#177078]). +* Adds grouping by multiple values when creating SLOs, allowing for dynamic creation of multiple SLOs from a single SLI definition ({kibana-pull}175063[#175063]). +Uptime:: +* Adds Monitor public API ({kibana-pull}169928[#169928]). + +For more information about the features introduced in 8.14.0, refer to <>. + +[[enhancements-and-bug-fixes-v8.14.0]] +=== Enhancements and bug fixes + +For detailed information about the 8.14.0 release, review the enhancements and bug fixes. + +[float] +[[enhancement-v8.14.0]] +=== Enhancements +Alerting:: +* Adds history chart for multiple conditions ({kibana-pull}180578[#180578]). +* Show Alerting rule JSON for API requests ({kibana-pull}180085[#180085]). +* Implement tabbed design for existing alert detail pages ({kibana-pull}179529[#179529]). +* Adds new rule type selection modal ({kibana-pull}179285[#179285]). +* Moves alerts filter controls to `@kbn/alerts-ui-shared` package ({kibana-pull}179243[#179243]). +* Improves alerts table actions column performance ({kibana-pull}178632[#178632]). +* Adds Insights component to alerts details ({kibana-pull}178330[#178330]). +* Adds support to dhow the number of additional filters that are applied on the alerts table ({kibana-pull}177275[#177275]). +* Adds error boundary to AlertsTable ({kibana-pull}176412[#176412]). +* Improves the performance of `join_by_key` ({kibana-pull}175177[#175177]). +APM:: +* Show Universal Profiling data on transaction details page ({kibana-pull}176922[#176922]). +Connectors:: +* Adds support for the Jira connector API to support the `otherFields` property to pass additional fields to be used when updating or creating issues via the link:https://developer.atlassian.com/cloud/jira/platform/rest/v2/api-group-issues/#api-rest-api-2-issue-post[Jira API] ({kibana-pull}178627[#178627]). +Dashboard:: +* Reorganized panel actions in the actions menu ({kibana-pull}178596[#178596]). +* Adds panel styling improvements ({kibana-pull}178139[#178139]). +* Adds "Apply" button to stop controls selections being automatically applied ({kibana-pull}174714[#174714]). +Discover:: +* Support field stats for {esql} query ({kibana-pull}178433[#178433]). +Elastic Security:: +For the Elastic Security 8.14.0 release information, refer to {security-guide}/release-notes.html[_Elastic Security Solution Release Notes_]. +ES|QL:: +* Implicit casting changes ({kibana-pull}182989[#182989]). +* Adds validation and auto-complete for `date_diff` ({kibana-pull}182513[#182513]). +* Adds more functions to the validator ({kibana-pull}180640[#180640]). +* Adds an enhanced chart switcher to the *Lens* inline editing flyout ({kibana-pull}177790[#177790]). +Fleet:: +* Adds support for dimension mappings in dynamic templates ({kibana-pull}180023[#180023]). +* Adds CPU metrics to request diagnostics ({kibana-pull}179819[#179819]). +* Adds Settings Framework API and UI ({kibana-pull}179795[#179795]). +* Adds an Elastic Defend advanced policy option for pruning capability arrays ({kibana-pull}179766[#179766]). +* Adds Agent activity flyout enhancements ({kibana-pull}179161[#179161]). +* Adds unhealthy reason (input/output/other) to agent metrics ({kibana-pull}178605[#178605]). +* Adds a warning which is displayed when trying to upgrade agent to version > max fleet server version ({kibana-pull}178079[#178079]). +Infrastructure:: +* Adds alerts count to hosts data ({kibana-pull}176034[#176034]). +Lens & Visualizations:: +* combines the chart type selection options into a single, layer-based chart switch ({kibana-pull}178971[#178971]). +Machine Learning:: +* Hides file upload document count chart until data is searchable ({kibana-pull}181460[#181460]). +* Removes technical preview badge for pattern analysis ({kibana-pull}181020[#181020]). +* Adds support for ad-hoc Data Views for testing models in Trained Models UI ({kibana-pull}180795[#180795]). +* Adds open and edit panel actions for the Single Metric Viewer ({kibana-pull}179364[#179364]). +* Improves {esql} data visualizer performance with early limit and remove option to Analyze all ({kibana-pull}179286[#179286]). +* Adds query history for the {esql} Data visualizer ({kibana-pull}179098[#179098]). +* Hides the Filebeat configuration card for Serverless Search file upload ({kibana-pull}178987[#178987]). +* Improves performance of Field stats / Index data visualizer by reducing requests for empty fields, making it convenient to add multi-field ({kibana-pull}178766[#178766]). +* AIOps: Identify spike/dips with change point detection for log rate analysis ({kibana-pull}178338[#178338]). +* Adds ML feature privileges tooltip ({kibana-pull}181595[#181595]). +Management:: +* Transforms: Use basic stats for transform list, call full stats only for expanded rows ({kibana-pull}180271[#180271]). +* Allows adding a custom description for data view fields ({kibana-pull}168577[#168577]). +Observability:: +* Adds an advanced setting to enable simulated function calling ({kibana-pull}180621[#180621]). +* Adds a public API for /chat/complete ({kibana-pull}179618[#179618]). +* Persists settings in {es} instead of local storage ({kibana-pull}179380[#179380]). +* Allows filtering data views by type ({kibana-pull}179069[#179069]). +* Implements contextual actions ({kibana-pull}178405[#178405]). +* Adds the ability to create an SLI based on the availability of your synthetics monitors ({kibana-pull}177842[#177842]). +* Adds setting for user's preferred language for the AI assistant ({kibana-pull}176444[#176444]). +* Adds improvements to the AI assistants handling where a generated {esql} query has syntax errors ({kibana-pull}179919[#179919]). +* Adds grouping by multiple values when creating SLOs, allowing for dynamic creation of multiple SLOs from a single SLI definition({kibana-pull}175063[#175063]). +Platform:: +* Adds a new option, `system`, to the `theme:darkMode` Kibana advanced setting, that can be used to have Kibana's theme follow the system's (light or dark) ({kibana-pull}173044[#173044]). +Reporting:: +* A feature has been deprecated which allowed users to download a CSV file from a saved search panel in a dashboard, without having a report generated. Now, when users need to access saved search data from a dashboard panel as CSV, a normal report will be generated. To access the deprecated functionality, you can add `xpack.reporting.csv.enablePanelActionDownload: true` to kibana.yml, but this ability will be removed in a future version of Kibana ({kibana-pull}178159[#178159]). +Security:: +* Adds `Content-Security-Policy-Report-Only` header support ({kibana-pull}179949[#179949]). +* Renders a user-friendly UI for unhandled login failures ({kibana-pull}173959[#173959]). +* Migrates the Security AI Assistant into a flyout ({kibana-pull}176657[#176657]). +* Adds support for LangChain streaming for the `openai-functions` agent ({kibana-pull}174126[#174126]). +Unified Search:: +* Adds auto-refresh pause when the page is not visible ({kibana-pull}177693[#177693]). +* Adds support for not clearing the value on the filter builder when the operator changes ({kibana-pull}176911[#176911]). + +[float] +[[fixes-v8.14.0]] +=== Bug Fixes +Alerting:: +* Fixes bug with aggregation building for {es} query rule when there are multi-terms and a group by field ({kibana-pull}182865[#182865]). +* Fixes using `recoveredCurrent` and `activeCurrent` to determine how to update old alerts ({kibana-pull}180934[#180934]). +* Fixes logging the errors reported by `addLastRunError` to the console ({kibana-pull}179962[#179962]). +* Preserves relative snooze when adding or removing snooze schedules ({kibana-pull}178344[#178344]). +* Reverts changes to notify when there is a change on connector configuration ({kibana-pull}177054[#177054]). +APM:: +* Fixes the cardinality count for SLOs generated from a single SLI definition was previously incorrect for APM latency and APM availability SLIs ({kibana-pull}183171[#183171]). +* Fixes the telemetry collection of Logstash with metricbeat monitoring ({kibana-pull}182304[#182304]). +* Fixes otel service detection ({kibana-pull}180574[#180574]). +Cases:: +* Displays the link to the Cases page under observability when Cases {kib} privileges are granted regardless of the other application privileges ({kibana-pull}182569[#182569]). +Canvas:: +* Fixes workpad templates using legacy filters function ({kibana-pull}176093[#176093]). +Connectors:: +* Removes secrets from the connectors before validating in `actionsClient` getAll ({kibana-pull}179837[#179837]). +Dashboard:: +* Fixes opening panel title edit flyout only when panel title is clicked ({kibana-pull}180137[#180137]). +* Disallows copy to dashboard from a maximized panel ({kibana-pull}179422[#179422]). +Discover:: +* Fixes issue where an ES query rule could be created with a data view, then the data view is changed but there's still a reference to the previous data view's timestamp field. ({kibana-pull}182883[#182883]). +* Fixes view all matches button for timestamps with numeric date formats ({kibana-pull}181769[#181769]). +* Fixes time range filters for CSV when a relative time filter is specified in UI ({kibana-pull}181067[#181067]). +* Fixes the status list to be static ({kibana-pull}177435[#177435]). +* Fixes a timeout for a "View all matches" request ({kibana-pull}181859[#181859]). +* Fixes tracking total hits for "View all matches" button ({kibana-pull}181811[#181811]). +* Fixes comments bugs in Discover and Data Visualizer ({kibana-pull}181283[#181283]). +* Fixes the problem with Discover and queries without the from command ({kibana-pull}180692[#180692]). +* Fixes displaying "Unsaved changes" badge on time filter changes in case time range is stored along with saved search ({kibana-pull}178659[#178659]). +Elastic Security:: +For the Elastic Security 8.14.0 release information, refer to {security-guide}/release-notes.html[_Elastic Security Solution Release Notes_]. +ES|QL:: +* Fixes validation on string implicit casting for dates and other minor issues ({kibana-pull}181571[#181571]). +* Fixes validation for some specific {esql} types ({kibana-pull}181381[#181381]). +* Fixes retrieving the indices from AST parsing ({kibana-pull}181271[#181271]). +* Fixes max and min accepting date fields ({kibana-pull}180945[#180945]). +* Fixes autocomplete with incompatible arguments ({kibana-pull}180874[#180874]). +* Fixes providing the CCS indices on the autosuggestion ({kibana-pull}180610[#180610]). +* Fixes to `auto_bucket` and constant-only parameters ({kibana-pull}180509[#180509]). +* Fixes persisting columns sorting in saved search ({kibana-pull}180193[#180193]). +* Fixes client-side validation: make `and` and `or` accept `null` ({kibana-pull}179707[#179707]). +* Fixes to the @timestamp column ({kibana-pull}176834[#176834]). +* Fixes validation running on outdated queries when typing ({kibana-pull}180977[#180977]). +Fleet:: +* Adds validation to dataset field in input packages to disallow special characters ({kibana-pull}182925[#182925]). +* Fixes rollback input package install on failure ({kibana-pull}182665[#182665]). +* Fixes cloudflare template error ({kibana-pull}182645[#182645]). +* Fixes displaying `Config` and `API reference` tabs if they are not needed ({kibana-pull}182518[#182518]). +* Fixes allowing fleet-server agent upgrade to newer than fleet-server ({kibana-pull}181575[#181575]). +* Fixes flattened inputs in the configuration tab ({kibana-pull}181155[#181155]). +* Adds callout when editing an output about plain text secrets being re-saved to secret storage ({kibana-pull}180334[#180334]). +* Removes unnecessary field definitions for custom integrations ({kibana-pull}178293[#178293]). +* Fixes secrets UI inputs in forms when secrets storage is disabled server side ({kibana-pull}178045[#178045]). +* Fixes not being able to preview or download files with special characters ({kibana-pull}176822[#176822]). +* Fixes KQL validation being applied in search boxes ({kibana-pull}176806[#176806]). +Lens & Visualizations:: +* Fixes import to other spaces ({kibana-pull}183076[#183076]). +* Fixes clip path cutting mobile view in *Lens* ({kibana-pull}182376[#182376]). +* Fixes error message layer indexing in *Lens* ({kibana-pull}180898[#180898]). +* Fixes markdown table borders being visible in the text panels ({kibana-pull}180454[#180454]). +* Fixes default formatter for gauge charts in *Lens* ({kibana-pull}179473[#179473]). +* Fixes error for non-date histogram charts that contain `showCurrentTimeMarker:true` setting in *Lens* ({kibana-pull}179452[#179452]). +* Fixes overriding title when using the inline *Lens* editor ({kibana-pull}182897[#182897]). +Machine Learning:: +* Single Metric Viewer: Ensures edit to different job works as expected ({kibana-pull}183086[#183086]). +* Single Metric Viewer: Fixes hover functionality in the anomalies table ({kibana-pull}182297[#182297]). +* Single Metric Viewer: Ensures chart displays correctly when opening from a job annotation ({kibana-pull}182176[#182176]). +* Single Metric Viewer: Displays error message when insufficient permissions ({kibana-pull}180858[#180858]). +* Fixes retention of categorization example limits ({kibana-pull}182103[#182103]). +* Fixes responsive layout for Trained Models table ({kibana-pull}181541[#181541]). +* Removes datafeed preview frozen tier message in serverless ({kibana-pull}181440[#181440]). +* ML anomaly swim lane: Ensure dashboard reset works correctly ({kibana-pull}181346[#181346]). +* AIOps: Fixes query string for the change point detection metric charts ({kibana-pull}181314[#181314]). +* AIOps: Fixes missing field caps filters for log rate analysis ({kibana-pull}181109[#181109]). +* AIOps: Fixes not running log rate analysis twice when no spike/dip is detected ({kibana-pull}180980[#180980]). +* Removes all SCSS files in favor of CSS ({kibana-pull}178314[#178314]). +* Fixes polling for blocked anomaly detection jobs ({kibana-pull}178246[#178246]). +* Adds trained model list permission UI tests ({kibana-pull}174045[#174045]). +Management:: +* Fixes transform health rule failure with a long list of continuous transforms ({kibana-pull}183153[#183153]). +* The runtime field creation modal now shows indexed values instead of source values in the preview pane ({kibana-pull}181246[#181246]). +Monitoring:: +* Fixes broken KQL filter for Cluster Health rule ({kibana-pull}183259[#183259]). +Observability:: +* Fixes Triggered column timezone and format ({kibana-pull}182653[#182653]). +* Fixes refetching data views on save ({kibana-pull}181033[#181033]). +* Allows editing of charts when {es} query fails ({kibana-pull}180500[#180500]). +* Fixes Agent ID not being parsed correctly ({kibana-pull}180301[#180301]). +* Changes `Custom KQL` to `Custom Query` ({kibana-pull}179497[#179497]). +* Fixes filtering for a histogram legend value ({kibana-pull}178551[#178551]). +* Fixes an OpenAI Connector default model assignment bug ({kibana-pull}178369[#178369]). +Platform:: +* Update static asset headers to include `public` and `immutable` link:https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control[cache control directives] to a large number of assets served by Kibana, which should reduce the number of requests for static assets in browsers that respect these directives. ({kibana-pull}180378[#180378]). +* Omits apiKey from RUM agent ({kibana-pull}178902[#178902]). +Presentation:: +* Fixes clicking "Explore in maps" button not taking users to maps ({kibana-pull}181903[#181903]). +Security:: +* Fixed escaped terminal codes logging in interactive plugin setup ({kibana-pull}180342[#180342]). +* Fixes an issue with Security Assistant send to timeline functionality ({kibana-pull}177771[#177771]). +SharedUX:: +* Fixes multiline query in expanded mode displaying undefined for line number ({kibana-pull}181544[#181544]). +* Removes unused legacy markdown component ({kibana-pull}179272[#179272]). +* Fixes typo in chromium driver factory page event ({kibana-pull}178708[#178708]). +* Fixes not being able to enter the {esql} editor when the column menu is open ({kibana-pull}178622[#178622]). +* Fixes an issue in Reporting with consistently showing the toast message for completed report jobs ({kibana-pull}177537[#177537]). +* Fixes time picker to show allowed formats properly in absolute tabs ({kibana-pull}182152[#182152]). [[release-notes-8.13.4]] == {kib} 8.13.4 diff --git a/docs/playground/playground-context.asciidoc b/docs/playground/playground-context.asciidoc index c0c4533fcb1a0..25273eb8806ba 100644 --- a/docs/playground/playground-context.asciidoc +++ b/docs/playground/playground-context.asciidoc @@ -15,6 +15,11 @@ There are a few ways to optimize this context for better results. Some adjustments can be made directly in the {x} UI. Others require refining your indexing strategy, and potentially reindexing your data. +[NOTE] +===== +Currently you can only select *one field* to be provided as context to the LLM. +===== + [float] [[playground-context-ui]] == Edit context in UI diff --git a/docs/settings/reporting-settings.asciidoc b/docs/settings/reporting-settings.asciidoc index e19065a533adc..f871f72db22c0 100644 --- a/docs/settings/reporting-settings.asciidoc +++ b/docs/settings/reporting-settings.asciidoc @@ -70,7 +70,9 @@ reports, you might need to change the following settings. If capturing a report fails for any reason, {kib} will re-queue the report job for retry, as many times as this setting. Defaults to `3`. `xpack.reporting.queue.indexInterval`:: -How often the index that stores reporting jobs rolls over to a new index. Valid values are `year`, `month`, `week`, `day`, and `hour`. Defaults to `week`. +deprecated:[8.15.0,This setting has no effect.] How often Reporting creates a new index to store report jobs and file contents. +Valid values are `year`, `month`, `week`, `day`, and `hour`. Defaults to `week`. +*NOTE*: This setting exists for backwards compatibility, but is unused. Use the built-in ILM policy provided for the reporting plugin to customize the rollover of Reporting data. [[xpack-reportingQueue-pollEnabled]] `xpack.reporting.queue.pollEnabled` :: When `true`, enables the {kib} instance to poll {es} for pending jobs and claim them for diff --git a/docs/user/reporting/index.asciidoc b/docs/user/reporting/index.asciidoc index 318a901b15e4c..338b2bc53a55a 100644 --- a/docs/user/reporting/index.asciidoc +++ b/docs/user/reporting/index.asciidoc @@ -67,10 +67,9 @@ NOTE: When you create a dashboard report that includes a data table or saved sea . To view and manage reports, open the main menu, then click *Stack Management > Reporting*. -NOTE: Reports are stored in {es} and managed by the `kibana-reporting` {ilm} -({ilm-init}) policy. By default, the policy stores reports forever. To learn -more about {ilm-init} policies, refer to the {es} -{ref}/index-lifecycle-management.html[{ilm-init} documentation]. +NOTE: In "stateful" deployments, reports are stored in {es} and managed by the `kibana-reporting` {ilm} +({ilm-init}) policy. By default, the policy stores reports forever. To learn more about {ilm-init} policies, refer +to the {es} {ref}/index-lifecycle-management.html[{ilm-init} documentation]. [float] [[csv-limitations]] diff --git a/docs/user/reporting/script-example.asciidoc b/docs/user/reporting/script-example.asciidoc index 937e140bd67a0..5445058ead03b 100644 --- a/docs/user/reporting/script-example.asciidoc +++ b/docs/user/reporting/script-example.asciidoc @@ -36,4 +36,4 @@ An example response for a successfully queued report: --------------------------------------------------------- <1> The relative path on the {kib} host for downloading the report. -<2> (Not included in the example) Internal representation of the reporting job, as found in the `.reporting-*` index. +<2> (Not included in the example) Internal representation of the reporting job, as found in the `.reporting-*` storage. diff --git a/examples/bfetch_explorer/public/mount.tsx b/examples/bfetch_explorer/public/mount.tsx index 40d171f2d98a3..9a09d40748137 100644 --- a/examples/bfetch_explorer/public/mount.tsx +++ b/examples/bfetch_explorer/public/mount.tsx @@ -10,6 +10,7 @@ import * as React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; import { CoreSetup, CoreStart, AppMountParameters } from '@kbn/core/public'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import { BfetchExplorerStartPlugins, ExplorerService } from './plugin'; import { App } from './containers/app'; @@ -26,9 +27,11 @@ export const mount = const [core, plugins] = await coreSetup.getStartServices(); const deps: BfetchDeps = { appBasePath, core, plugins, explorer }; const reactElement = ( - - - + + + + + ); render(reactElement, element); return () => unmountComponentAtNode(element); diff --git a/examples/bfetch_explorer/tsconfig.json b/examples/bfetch_explorer/tsconfig.json index e09ad294b4ae7..c8417c734f58d 100644 --- a/examples/bfetch_explorer/tsconfig.json +++ b/examples/bfetch_explorer/tsconfig.json @@ -19,5 +19,6 @@ "@kbn/bfetch-plugin", "@kbn/kibana-react-plugin", "@kbn/shared-ux-router", + "@kbn/react-kibana-context-render", ] } diff --git a/examples/content_management_examples/public/examples/index.tsx b/examples/content_management_examples/public/examples/index.tsx index 3b92da0ba025e..7b6296a80fb4d 100644 --- a/examples/content_management_examples/public/examples/index.tsx +++ b/examples/content_management_examples/public/examples/index.tsx @@ -9,6 +9,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { Redirect } from 'react-router-dom'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import { Router, Routes, Route } from '@kbn/shared-ux-router'; import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app'; import { EuiPageTemplate, EuiSideNav } from '@elastic/eui'; @@ -24,65 +25,67 @@ export const renderApp = ( { element, history }: AppMountParameters ) => { ReactDOM.render( - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - , + + + + + + + + + + + + + + + + + + , element ); diff --git a/examples/content_management_examples/tsconfig.json b/examples/content_management_examples/tsconfig.json index c94193dc151cc..44b5bf053aeb6 100644 --- a/examples/content_management_examples/tsconfig.json +++ b/examples/content_management_examples/tsconfig.json @@ -29,5 +29,6 @@ "@kbn/shared-ux-router", "@kbn/saved-objects-finder-plugin", "@kbn/content-management-table-list-view-common", + "@kbn/react-kibana-context-render", ] } diff --git a/examples/developer_examples/public/app.tsx b/examples/developer_examples/public/app.tsx index b95806edb28eb..279697d5a200f 100644 --- a/examples/developer_examples/public/app.tsx +++ b/examples/developer_examples/public/app.tsx @@ -22,16 +22,29 @@ import { EuiLink, EuiButtonIcon, } from '@elastic/eui'; -import { AppMountParameters } from '@kbn/core/public'; +import { + AnalyticsServiceStart, + AppMountParameters, + I18nStart, + ThemeServiceStart, +} from '@kbn/core/public'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import { ExampleDefinition } from './types'; +interface StartServices { + analytics: Pick; + i18n: I18nStart; + theme: Pick; +} + interface Props { + startServices: StartServices; examples: ExampleDefinition[]; navigateToApp: (appId: string) => void; getUrlForApp: (appId: string) => string; } -function DeveloperExamples({ examples, navigateToApp, getUrlForApp }: Props) { +function DeveloperExamples({ startServices, examples, navigateToApp, getUrlForApp }: Props) { const [search, setSearch] = useState(''); const lcSearch = search.toLowerCase(); @@ -44,7 +57,7 @@ function DeveloperExamples({ examples, navigateToApp, getUrlForApp }: Props) { }); return ( - <> + @@ -103,7 +116,7 @@ function DeveloperExamples({ examples, navigateToApp, getUrlForApp }: Props) { ))} - + ); } diff --git a/examples/developer_examples/public/plugin.ts b/examples/developer_examples/public/plugin.ts index c87bd2f5cc890..75a304b895e8f 100644 --- a/examples/developer_examples/public/plugin.ts +++ b/examples/developer_examples/public/plugin.ts @@ -27,8 +27,10 @@ export class DeveloperExamplesPlugin implements Plugin coreStart.application.navigateToApp(appId), getUrlForApp: (appId: string) => coreStart.application.getUrlForApp(appId), diff --git a/examples/developer_examples/tsconfig.json b/examples/developer_examples/tsconfig.json index fdd37bde1e1eb..3863ff54e0b96 100644 --- a/examples/developer_examples/tsconfig.json +++ b/examples/developer_examples/tsconfig.json @@ -14,6 +14,7 @@ "target/**/*", ], "kbn_references": [ - "@kbn/core" + "@kbn/core", + "@kbn/react-kibana-context-render" ] } diff --git a/examples/discover_customization_examples/public/plugin.tsx b/examples/discover_customization_examples/public/plugin.tsx index 8afe18cbe9c92..d1215307fdb60 100644 --- a/examples/discover_customization_examples/public/plugin.tsx +++ b/examples/discover_customization_examples/public/plugin.tsx @@ -16,6 +16,7 @@ import { } from '@elastic/eui'; import { CoreSetup, CoreStart, Plugin, SimpleSavedObject } from '@kbn/core/public'; import type { DeveloperExamplesSetup } from '@kbn/developer-examples-plugin/public'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import type { CustomizationCallback, DiscoverSetup, @@ -140,41 +141,43 @@ export class DiscoverCustomizationExamplesPlugin implements Plugin { document.body.appendChild(optionsContainer); const element = ( - - alert('Create new clicked'), - }, - { - name: 'Make a copy', - icon: 'copy', - onClick: () => alert('Make a copy clicked'), - }, - { - name: 'Manage saved searches', - icon: 'gear', - onClick: () => alert('Manage saved searches clicked'), - }, - ], - }, - ]} - data-test-subj="customOptionsPopover" - /> - + + + alert('Create new clicked'), + }, + { + name: 'Make a copy', + icon: 'copy', + onClick: () => alert('Make a copy clicked'), + }, + { + name: 'Manage saved searches', + icon: 'gear', + onClick: () => alert('Manage saved searches clicked'), + }, + ], + }, + ]} + data-test-subj="customOptionsPopover" + /> + + ); ReactDOM.render(element, optionsContainer); diff --git a/examples/discover_customization_examples/tsconfig.json b/examples/discover_customization_examples/tsconfig.json index c71a72086dde1..49c83477e0c1f 100644 --- a/examples/discover_customization_examples/tsconfig.json +++ b/examples/discover_customization_examples/tsconfig.json @@ -14,6 +14,7 @@ "@kbn/i18n-react", "@kbn/react-kibana-context-theme", "@kbn/data-plugin", + "@kbn/react-kibana-context-render", ], "exclude": ["target/**/*"] } diff --git a/examples/embeddable_examples/public/app/render_examples.tsx b/examples/embeddable_examples/public/app/render_examples.tsx index f956a71711c7c..4998b3bc5a59c 100644 --- a/examples/embeddable_examples/public/app/render_examples.tsx +++ b/examples/embeddable_examples/public/app/render_examples.tsx @@ -27,19 +27,14 @@ import { SEARCH_EMBEDDABLE_ID } from '../react_embeddables/search/constants'; import type { SearchApi, SearchSerializedState } from '../react_embeddables/search/types'; export const RenderExamples = () => { - const initialState = useMemo(() => { - return { - rawState: { - timeRange: undefined, - }, - references: [], - }; - // only run onMount - }, []); - const parentApi = useMemo(() => { return { reload$: new Subject(), + getSerializedStateForChild: () => ({ + rawState: { + timeRange: undefined, + }, + }), timeRange$: new BehaviorSubject({ from: 'now-24h', to: 'now', @@ -85,8 +80,7 @@ export const RenderExamples = () => { {` type={SEARCH_EMBEDDABLE_ID} - state={initialState} - parentApi={parentApi} + getParentApi={() => parentApi} onApiAvailable={(newApi) => { setApi(newApi); }} @@ -107,8 +101,7 @@ export const RenderExamples = () => { key={hidePanelChrome ? 'hideChrome' : 'showChrome'} type={SEARCH_EMBEDDABLE_ID} - state={initialState} - parentApi={parentApi} + getParentApi={() => parentApi} onApiAvailable={(newApi) => { setApi(newApi); }} diff --git a/examples/embeddable_examples/public/plugin.ts b/examples/embeddable_examples/public/plugin.ts index bcac6bf4d1367..f17bf97db11fd 100644 --- a/examples/embeddable_examples/public/plugin.ts +++ b/examples/embeddable_examples/public/plugin.ts @@ -21,9 +21,11 @@ import { DATA_TABLE_ID } from './react_embeddables/data_table/constants'; import { registerCreateDataTableAction } from './react_embeddables/data_table/create_data_table_action'; import { EUI_MARKDOWN_ID } from './react_embeddables/eui_markdown/constants'; import { registerCreateEuiMarkdownAction } from './react_embeddables/eui_markdown/create_eui_markdown_action'; -import { registerCreateFieldListAction } from './react_embeddables/field_list/create_field_list_action'; import { FIELD_LIST_ID } from './react_embeddables/field_list/constants'; +import { registerCreateFieldListAction } from './react_embeddables/field_list/create_field_list_action'; import { registerFieldListPanelPlacementSetting } from './react_embeddables/field_list/register_field_list_embeddable'; +import { SAVED_BOOK_ID } from './react_embeddables/saved_book/constants'; +import { registerCreateSavedBookAction } from './react_embeddables/saved_book/create_saved_book_action'; import { registerAddSearchPanelAction } from './react_embeddables/search/register_add_search_panel_action'; import { registerSearchEmbeddable } from './react_embeddables/search/register_search_embeddable'; @@ -73,6 +75,14 @@ export class EmbeddableExamplesPlugin implements Plugin { + const { getSavedBookEmbeddableFactory } = await import( + './react_embeddables/saved_book/saved_book_react_embeddable' + ); + const [coreStart] = await startServicesPromise; + return getSavedBookEmbeddableFactory(coreStart); + }); + registerSearchEmbeddable( embeddable, new Promise((resolve) => startServicesPromise.then(([_, startDeps]) => resolve(startDeps))) @@ -88,6 +98,8 @@ export class EmbeddableExamplesPlugin implements Plugin { + const bookTitle = new BehaviorSubject(attributes.bookTitle); + const authorName = new BehaviorSubject(attributes.authorName); + const numberOfPages = new BehaviorSubject(attributes.numberOfPages); + const bookSynopsis = new BehaviorSubject(attributes.bookSynopsis); + + return { + bookTitle, + authorName, + numberOfPages, + bookSynopsis, + comparators: { + bookTitle: [bookTitle, (val) => bookTitle.next(val)], + authorName: [authorName, (val) => authorName.next(val)], + numberOfPages: [numberOfPages, (val) => numberOfPages.next(val)], + bookSynopsis: [bookSynopsis, (val) => bookSynopsis.next(val)], + }, + }; +}; + +export const serializeBookAttributes = (stateManager: BookAttributesManager): BookAttributes => ({ + bookTitle: stateManager.bookTitle.value, + authorName: stateManager.authorName.value, + numberOfPages: stateManager.numberOfPages.value, + bookSynopsis: stateManager.bookSynopsis.value, +}); diff --git a/packages/solution-nav/es/index.ts b/examples/embeddable_examples/public/react_embeddables/saved_book/constants.ts similarity index 78% rename from packages/solution-nav/es/index.ts rename to examples/embeddable_examples/public/react_embeddables/saved_book/constants.ts index 8024948fb3cd1..4da3ebecf477e 100644 --- a/packages/solution-nav/es/index.ts +++ b/examples/embeddable_examples/public/react_embeddables/saved_book/constants.ts @@ -6,4 +6,5 @@ * Side Public License, v 1. */ -export { definition } from './definition'; +export const SAVED_BOOK_ID = 'book'; +export const ADD_SAVED_BOOK_ACTION_ID = 'create_saved_book'; diff --git a/examples/embeddable_examples/public/react_embeddables/saved_book/create_saved_book_action.tsx b/examples/embeddable_examples/public/react_embeddables/saved_book/create_saved_book_action.tsx new file mode 100644 index 0000000000000..6916bd38cc28d --- /dev/null +++ b/examples/embeddable_examples/public/react_embeddables/saved_book/create_saved_book_action.tsx @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { CoreStart } from '@kbn/core/public'; +import { i18n } from '@kbn/i18n'; +import { apiIsPresentationContainer } from '@kbn/presentation-containers'; +import { EmbeddableApiContext } from '@kbn/presentation-publishing'; +import { IncompatibleActionError } from '@kbn/ui-actions-plugin/public'; +import { UiActionsPublicStart } from '@kbn/ui-actions-plugin/public/plugin'; +import { embeddableExamplesGrouping } from '../embeddable_examples_grouping'; +import { + defaultBookAttributes, + serializeBookAttributes, + stateManagerFromAttributes, +} from './book_state'; +import { ADD_SAVED_BOOK_ACTION_ID, SAVED_BOOK_ID } from './constants'; +import { openSavedBookEditor } from './saved_book_editor'; +import { saveBookAttributes } from './saved_book_library'; +import { + BookByReferenceSerializedState, + BookByValueSerializedState, + BookSerializedState, +} from './types'; + +export const registerCreateSavedBookAction = (uiActions: UiActionsPublicStart, core: CoreStart) => { + uiActions.registerAction({ + id: ADD_SAVED_BOOK_ACTION_ID, + getIconType: () => 'folderClosed', + grouping: [embeddableExamplesGrouping], + isCompatible: async ({ embeddable }) => { + return apiIsPresentationContainer(embeddable); + }, + execute: async ({ embeddable }) => { + if (!apiIsPresentationContainer(embeddable)) throw new IncompatibleActionError(); + const newPanelStateManager = stateManagerFromAttributes(defaultBookAttributes); + + const { addToLibrary } = await openSavedBookEditor(newPanelStateManager, true, core, { + parentApi: embeddable, + }); + + const initialState: BookSerializedState = await (async () => { + // if we're adding this to the library, we only need to return the by reference state. + if (addToLibrary) { + const savedBookId = await saveBookAttributes( + undefined, + serializeBookAttributes(newPanelStateManager) + ); + return { savedBookId } as BookByReferenceSerializedState; + } + return { + attributes: serializeBookAttributes(newPanelStateManager), + } as BookByValueSerializedState; + })(); + + embeddable.addNewPanel({ + panelType: SAVED_BOOK_ID, + initialState, + }); + }, + getDisplayName: () => + i18n.translate('embeddableExamples.savedbook.addBookAction.displayName', { + defaultMessage: 'Book', + }), + }); + uiActions.attachAction('ADD_PANEL_TRIGGER', ADD_SAVED_BOOK_ACTION_ID); +}; diff --git a/examples/embeddable_examples/public/react_embeddables/saved_book/saved_book_editor.tsx b/examples/embeddable_examples/public/react_embeddables/saved_book/saved_book_editor.tsx new file mode 100644 index 0000000000000..d658b8fac1e9e --- /dev/null +++ b/examples/embeddable_examples/public/react_embeddables/saved_book/saved_book_editor.tsx @@ -0,0 +1,212 @@ +/* + * Copyright 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 { + EuiButton, + EuiButtonEmpty, + EuiFieldNumber, + EuiFieldText, + EuiFlexGroup, + EuiFlexItem, + EuiFlyoutBody, + EuiFlyoutFooter, + EuiFlyoutHeader, + EuiFormControlLayout, + EuiFormRow, + EuiSwitch, + EuiTextArea, + EuiTitle, +} from '@elastic/eui'; +import { CoreStart } from '@kbn/core-lifecycle-browser'; +import { OverlayRef } from '@kbn/core-mount-utils-browser'; +import { i18n } from '@kbn/i18n'; +import { tracksOverlays } from '@kbn/presentation-containers'; +import { + apiHasParentApi, + apiHasUniqueId, + useBatchedOptionalPublishingSubjects, +} from '@kbn/presentation-publishing'; +import { toMountPoint } from '@kbn/react-kibana-mount'; +import React from 'react'; +import { serializeBookAttributes } from './book_state'; +import { BookAttributesManager } from './types'; + +export const openSavedBookEditor = ( + attributesManager: BookAttributesManager, + isCreate: boolean, + core: CoreStart, + api: unknown +): Promise<{ addToLibrary: boolean }> => { + return new Promise((resolve) => { + const closeOverlay = (overlayRef: OverlayRef) => { + if (apiHasParentApi(api) && tracksOverlays(api.parentApi)) { + api.parentApi.clearOverlays(); + } + overlayRef.close(); + }; + + const initialState = serializeBookAttributes(attributesManager); + const overlay = core.overlays.openFlyout( + toMountPoint( + { + // set the state back to the initial state and reject + attributesManager.authorName.next(initialState.authorName); + attributesManager.bookSynopsis.next(initialState.bookSynopsis); + attributesManager.bookTitle.next(initialState.bookTitle); + attributesManager.numberOfPages.next(initialState.numberOfPages); + closeOverlay(overlay); + }} + onSubmit={(addToLibrary: boolean) => { + closeOverlay(overlay); + resolve({ addToLibrary }); + }} + />, + { + theme: core.theme, + i18n: core.i18n, + } + ), + { + type: isCreate ? 'overlay' : 'push', + size: isCreate ? 'm' : 's', + onClose: () => closeOverlay(overlay), + } + ); + + const overlayOptions = !isCreate && apiHasUniqueId(api) ? { focusedPanelId: api.uuid } : {}; + /** + * if our parent needs to know about the overlay, notify it. This allows the parent to close the overlay + * when navigating away, or change certain behaviors based on the overlay being open. + */ + if (apiHasParentApi(api) && tracksOverlays(api.parentApi)) { + api.parentApi.openOverlay(overlay, overlayOptions); + } + }); +}; + +export const SavedBookEditor = ({ + attributesManager, + isCreate, + onSubmit, + onCancel, +}: { + attributesManager: BookAttributesManager; + isCreate: boolean; + onSubmit: (addToLibrary: boolean) => void; + onCancel: () => void; +}) => { + const [addToLibrary, setAddToLibrary] = React.useState(false); + const [authorName, synopsis, bookTitle, numberOfPages] = useBatchedOptionalPublishingSubjects( + attributesManager.authorName, + attributesManager.bookSynopsis, + attributesManager.bookTitle, + attributesManager.numberOfPages + ); + + return ( + <> + + +

+ {isCreate + ? i18n.translate('embeddableExamples.savedBook.editor.newTitle', { + defaultMessage: 'Create new book', + }) + : i18n.translate('embeddableExamples.savedBook.editor.editTitle', { + defaultMessage: 'Edit book', + })} +

+
+
+ + + + attributesManager.authorName.next(e.target.value)} + /> + + + attributesManager.bookTitle.next(e.target.value)} + /> + + + attributesManager.numberOfPages.next(+e.target.value)} + /> + + + attributesManager.bookSynopsis.next(e.target.value)} + /> + + + + + + + + {i18n.translate('embeddableExamples.savedBook.editor.cancel', { + defaultMessage: 'Discard changes', + })} + + + + + {isCreate && ( + + setAddToLibrary(!addToLibrary)} + /> + + )} + + onSubmit(addToLibrary)} fill> + {isCreate + ? i18n.translate('embeddableExamples.savedBook.editor.create', { + defaultMessage: 'Create book', + }) + : i18n.translate('embeddableExamples.savedBook.editor.save', { + defaultMessage: 'Keep changes', + })} + + + + + + + + ); +}; diff --git a/examples/embeddable_examples/public/react_embeddables/saved_book/saved_book_library.ts b/examples/embeddable_examples/public/react_embeddables/saved_book/saved_book_library.ts new file mode 100644 index 0000000000000..49b42ad2b96bf --- /dev/null +++ b/examples/embeddable_examples/public/react_embeddables/saved_book/saved_book_library.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { Storage } from '@kbn/kibana-utils-plugin/public'; +import { v4 } from 'uuid'; +import { BookAttributes } from './types'; + +const storage = new Storage(localStorage); + +export const loadBookAttributes = async (id: string): Promise => { + await new Promise((r) => setTimeout(r, 500)); // simulate load from network. + const attributes = storage.get(id) as BookAttributes; + return attributes; +}; + +export const saveBookAttributes = async ( + maybeId?: string, + attributes?: BookAttributes +): Promise => { + await new Promise((r) => setTimeout(r, 100)); // simulate save to network. + const id = maybeId ?? v4(); + storage.set(id, attributes); + return id; +}; diff --git a/examples/embeddable_examples/public/react_embeddables/saved_book/saved_book_react_embeddable.tsx b/examples/embeddable_examples/public/react_embeddables/saved_book/saved_book_react_embeddable.tsx new file mode 100644 index 0000000000000..94e54b6ee350c --- /dev/null +++ b/examples/embeddable_examples/public/react_embeddables/saved_book/saved_book_react_embeddable.tsx @@ -0,0 +1,211 @@ +/* + * Copyright 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 { EuiBadge, EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiText, EuiTitle } from '@elastic/eui'; +import { css } from '@emotion/react'; +import { CoreStart } from '@kbn/core-lifecycle-browser'; +import { ReactEmbeddableFactory } from '@kbn/embeddable-plugin/public'; +import { i18n } from '@kbn/i18n'; +import { + initializeTitles, + SerializedTitles, + useBatchedPublishingSubjects, +} from '@kbn/presentation-publishing'; +import { euiThemeVars } from '@kbn/ui-theme'; +import React from 'react'; +import { BehaviorSubject } from 'rxjs'; +import { serializeBookAttributes, stateManagerFromAttributes } from './book_state'; +import { SAVED_BOOK_ID } from './constants'; +import { openSavedBookEditor } from './saved_book_editor'; +import { loadBookAttributes, saveBookAttributes } from './saved_book_library'; +import { + BookApi, + BookAttributes, + BookByReferenceSerializedState, + BookByValueSerializedState, + BookRuntimeState, + BookSerializedState, +} from './types'; + +const bookSerializedStateIsByReference = ( + state?: BookSerializedState +): state is BookByReferenceSerializedState => { + return Boolean(state && (state as BookByReferenceSerializedState).savedBookId !== undefined); +}; + +export const getSavedBookEmbeddableFactory = (core: CoreStart) => { + const savedBookEmbeddableFactory: ReactEmbeddableFactory< + BookSerializedState, + BookApi, + BookRuntimeState + > = { + type: SAVED_BOOK_ID, + deserializeState: async (serializedState) => { + // panel state is always stored with the parent. + const titlesState: SerializedTitles = { + title: serializedState.rawState.title, + hidePanelTitles: serializedState.rawState.hidePanelTitles, + description: serializedState.rawState.description, + }; + + const savedBookId = bookSerializedStateIsByReference(serializedState.rawState) + ? serializedState.rawState.savedBookId + : undefined; + + const attributes: BookAttributes = bookSerializedStateIsByReference(serializedState.rawState) + ? await loadBookAttributes(serializedState.rawState.savedBookId)! + : serializedState.rawState.attributes; + + // Combine the serialized state from the parent with the state from the + // external store to build runtime state. + return { + ...titlesState, + ...attributes, + savedBookId, + }; + }, + buildEmbeddable: async (state, buildApi) => { + const { titlesApi, titleComparators, serializeTitles } = initializeTitles(state); + const bookAttributesManager = stateManagerFromAttributes(state); + const savedBookId$ = new BehaviorSubject(state.savedBookId); + + const api = buildApi( + { + ...titlesApi, + onEdit: async () => { + openSavedBookEditor(bookAttributesManager, false, core, api); + }, + isEditingEnabled: () => true, + getTypeDisplayName: () => + i18n.translate('embeddableExamples.savedbook.editBook.displayName', { + defaultMessage: 'book', + }), + serializeState: async () => { + if (savedBookId$.value === undefined) { + // if this book is currently by value, we serialize the entire state. + const bookByValueState: BookByValueSerializedState = { + attributes: serializeBookAttributes(bookAttributesManager), + ...serializeTitles(), + }; + return { rawState: bookByValueState }; + } + + // if this book is currently by reference, we serialize the reference and write to the external store. + const bookByReferenceState: BookByReferenceSerializedState = { + savedBookId: savedBookId$.value, + ...serializeTitles(), + }; + + await saveBookAttributes( + savedBookId$.value, + serializeBookAttributes(bookAttributesManager) + ); + return { rawState: bookByReferenceState }; + }, + + // in place library transforms + libraryId$: savedBookId$, + saveToLibrary: async (newTitle: string) => { + bookAttributesManager.bookTitle.next(newTitle); + const newId = await saveBookAttributes( + undefined, + serializeBookAttributes(bookAttributesManager) + ); + savedBookId$.next(newId); + return newId; + }, + checkForDuplicateTitle: async (title) => {}, + unlinkFromLibrary: () => { + savedBookId$.next(undefined); + }, + }, + { + savedBookId: [savedBookId$, (val) => savedBookId$.next(val)], + ...bookAttributesManager.comparators, + ...titleComparators, + } + ); + + return { + api, + Component: () => { + const [authorName, numberOfPages, savedBookId, bookTitle, synopsis] = + useBatchedPublishingSubjects( + bookAttributesManager.authorName, + bookAttributesManager.numberOfPages, + savedBookId$, + bookAttributesManager.bookTitle, + bookAttributesManager.bookSynopsis + ); + + return ( +
+ +
+ + + + {bookTitle} + + + + + + + {authorName} + + + + + {i18n.translate('embeddableExamples.savedBook.numberOfPages', { + defaultMessage: '{numberOfPages} pages', + values: { numberOfPages }, + })} + + + + + + {synopsis} + + +
+
+ ); + }, + }; + }, + }; + return savedBookEmbeddableFactory; +}; diff --git a/examples/embeddable_examples/public/react_embeddables/saved_book/types.ts b/examples/embeddable_examples/public/react_embeddables/saved_book/types.ts new file mode 100644 index 0000000000000..ec855bbd38f96 --- /dev/null +++ b/examples/embeddable_examples/public/react_embeddables/saved_book/types.ts @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { DefaultEmbeddableApi } from '@kbn/embeddable-plugin/public'; +import { + HasEditCapabilities, + HasInPlaceLibraryTransforms, + SerializedTitles, + StateComparators, +} from '@kbn/presentation-publishing'; +import { BehaviorSubject } from 'rxjs'; + +export interface BookAttributes { + bookTitle: string; + authorName: string; + numberOfPages: number; + bookSynopsis?: string; +} + +export type BookAttributesManager = { + [key in keyof Required]: BehaviorSubject; +} & { comparators: StateComparators }; + +export interface BookByValueSerializedState { + attributes: BookAttributes; +} + +export interface BookByReferenceSerializedState { + savedBookId: string; +} + +export type BookSerializedState = SerializedTitles & + (BookByValueSerializedState | BookByReferenceSerializedState); + +/** + * Book runtime state is a flattened version of all possible state keys. + */ +export interface BookRuntimeState + extends BookAttributes, + Partial, + SerializedTitles {} + +export type BookApi = DefaultEmbeddableApi & + HasEditCapabilities & + HasInPlaceLibraryTransforms; diff --git a/examples/embeddable_examples/public/react_embeddables/search/register_add_search_panel_action.tsx b/examples/embeddable_examples/public/react_embeddables/search/register_add_search_panel_action.tsx index 18bd40fe69dae..945e969187631 100644 --- a/examples/embeddable_examples/public/react_embeddables/search/register_add_search_panel_action.tsx +++ b/examples/embeddable_examples/public/react_embeddables/search/register_add_search_panel_action.tsx @@ -27,10 +27,16 @@ export const registerAddSearchPanelAction = (uiActions: UiActionsStart) => { embeddable.addNewPanel( { panelType: SEARCH_EMBEDDABLE_ID, + initialState: {}, }, true ); }, }); uiActions.attachAction('ADD_PANEL_TRIGGER', ADD_SEARCH_ACTION_ID); + if (uiActions.hasTrigger('ADD_CANVAS_ELEMENT_TRIGGER')) { + // Because Canvas is not enabled in Serverless, this trigger might not be registered - only attach + // the create action if the Canvas-specific trigger does indeed exist. + uiActions.attachAction('ADD_CANVAS_ELEMENT_TRIGGER', ADD_SEARCH_ACTION_ID); + } }; diff --git a/examples/embeddable_examples/public/react_embeddables/search/search_embeddable_renderer.tsx b/examples/embeddable_examples/public/react_embeddables/search/search_embeddable_renderer.tsx index cadaedbc29f6f..fcd1210f05b8d 100644 --- a/examples/embeddable_examples/public/react_embeddables/search/search_embeddable_renderer.tsx +++ b/examples/embeddable_examples/public/react_embeddables/search/search_embeddable_renderer.tsx @@ -6,10 +6,10 @@ * Side Public License, v 1. */ -import React, { useEffect, useMemo } from 'react'; -import { BehaviorSubject } from 'rxjs'; +import React, { useMemo } from 'react'; import { TimeRange } from '@kbn/es-query'; import { ReactEmbeddableRenderer } from '@kbn/embeddable-plugin/public'; +import { useSearchApi } from '@kbn/presentation-publishing'; import type { SearchApi, SearchSerializedState } from './types'; import { SEARCH_EMBEDDABLE_ID } from './constants'; @@ -28,23 +28,15 @@ export function SearchEmbeddableRenderer(props: Props) { // only run onMount }, []); - const parentApi = useMemo(() => { - return { - timeRange$: new BehaviorSubject(props.timeRange), - }; - // only run onMount - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - useEffect(() => { - parentApi.timeRange$.next(props.timeRange); - }, [props.timeRange, parentApi.timeRange$]); + const searchApi = useSearchApi({ timeRange: props.timeRange }); return ( type={SEARCH_EMBEDDABLE_ID} - state={initialState} - parentApi={parentApi} + getParentApi={() => ({ + ...searchApi, + getSerializedStateForChild: () => initialState, + })} hidePanelChrome={true} /> ); diff --git a/examples/embeddable_examples/tsconfig.json b/examples/embeddable_examples/tsconfig.json index b356083a20546..2df5e6534bd27 100644 --- a/examples/embeddable_examples/tsconfig.json +++ b/examples/embeddable_examples/tsconfig.json @@ -38,6 +38,8 @@ "@kbn/kibana-react-plugin", "@kbn/react-kibana-context-render", "@kbn/unified-data-table", - "@kbn/kibana-utils-plugin" + "@kbn/kibana-utils-plugin", + "@kbn/core-mount-utils-browser", + "@kbn/react-kibana-mount" ] } diff --git a/examples/error_boundary/public/plugin.tsx b/examples/error_boundary/public/plugin.tsx index 2c5d4e7487005..d09edbf714cc8 100755 --- a/examples/error_boundary/public/plugin.tsx +++ b/examples/error_boundary/public/plugin.tsx @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import { EuiButton } from '@elastic/eui'; +import { EuiButton, EuiProvider } from '@elastic/eui'; import React, { useState } from 'react'; import ReactDOM from 'react-dom'; @@ -74,23 +74,27 @@ export class ErrorBoundaryExamplePlugin implements Plugin id: 'errorBoundaryExample', title: 'Error Boundary Example', async mount({ element }: AppMountParameters) { + // Using the "EuiProvider" here rather than KibanaRenderContextProvider, because KibanaRenderContextProvider + // wraps KibanaErrorBoundaryProvider and KibanaErrorBoundary and we want to test it directly, not a wrapper. ReactDOM.render( - - - - - - - - - - - - - , + + + + + + + + + + + + + + + , element ); return () => ReactDOM.unmountComponentAtNode(element); diff --git a/examples/expressions_explorer/public/app.tsx b/examples/expressions_explorer/public/app.tsx index 776d612fd395d..029690d52fa4a 100644 --- a/examples/expressions_explorer/public/app.tsx +++ b/examples/expressions_explorer/public/app.tsx @@ -18,11 +18,17 @@ import { EuiText, EuiLink, } from '@elastic/eui'; -import { AppMountParameters, IUiSettingsClient, ThemeServiceStart } from '@kbn/core/public'; +import { + AppMountParameters, + I18nStart, + IUiSettingsClient, + ThemeServiceStart, +} from '@kbn/core/public'; import { ExpressionsStart } from '@kbn/expressions-plugin/public'; import { Start as InspectorStart } from '@kbn/inspector-plugin/public'; import { UiActionsStart } from '@kbn/ui-actions-plugin/public'; import { createKibanaReactContext } from '@kbn/kibana-react-plugin/public'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import { SettingsStart } from '@kbn/core-ui-settings-browser'; import { RunExpressionsExample } from './run_expressions'; import { RenderExpressionsExample } from './render_expressions'; @@ -36,6 +42,7 @@ interface Props { uiSettings: IUiSettingsClient; settings: SettingsStart; theme: ThemeServiceStart; + i18n: I18nStart; } const ExpressionsExplorer = ({ @@ -44,6 +51,7 @@ const ExpressionsExplorer = ({ actions, uiSettings, settings, + i18n, theme, }: Props) => { const { Provider: KibanaReactContextProvider } = createKibanaReactContext({ @@ -51,49 +59,52 @@ const ExpressionsExplorer = ({ settings, theme, }); + const startServices = { i18n, theme }; return ( - - - - - - - + + + + - -

- There are a couple of ways to run the expressions. Below some of the options are - demonstrated. You can read more about it{' '} - - here - -

-
+ +
+ + + +

+ There are a couple of ways to run the expressions. Below some of the options are + demonstrated. You can read more about it{' '} + + here + +

+
- + - + - + - + - + - + - + - -
-
-
-
-
+ + +
+
+
+
+ ); }; diff --git a/examples/expressions_explorer/public/plugin.tsx b/examples/expressions_explorer/public/plugin.tsx index ba95f55f0a19a..5fad13ec5e025 100644 --- a/examples/expressions_explorer/public/plugin.tsx +++ b/examples/expressions_explorer/public/plugin.tsx @@ -14,7 +14,7 @@ import { UiActionsStart, UiActionsSetup } from '@kbn/ui-actions-plugin/public'; import { getExpressionsInspectorViewDescription } from './inspector'; import { NAVIGATE_TRIGGER_ID, navigateTrigger } from './actions/navigate_trigger'; import { ACTION_NAVIGATE, createNavigateAction } from './actions/navigate_action'; -import { buttonRenderer } from './renderers/button'; +import { getButtonRenderer } from './renderers/button'; import { buttonFn } from './functions/button'; interface StartDeps { @@ -41,7 +41,7 @@ export class ExpressionsExplorerPlugin implements Plugin = { - name: 'button', - displayName: 'Button', - reuseDomNode: true, - render(domNode, config, handlers) { - const buttonClick = () => { - handlers.event({ - name: 'NAVIGATE', - data: { - href: config.href, - }, - }); - }; +export const getButtonRenderer = (core: CoreSetup) => { + const buttonRenderer: ExpressionRenderDefinition = { + name: 'button', + displayName: 'Button', + reuseDomNode: true, + async render(domNode, config, handlers) { + const [startServices] = await core.getStartServices(); + const buttonClick = () => { + handlers.event({ + name: 'NAVIGATE', + data: { + href: config.href, + }, + }); + }; - const renderDebug = () => ( -
- - {config.name} - -
- ); + const renderDebug = () => ( + +
+ + {config.name} + +
+
+ ); - ReactDOM.render(renderDebug(), domNode, () => handlers.done()); + ReactDOM.render(renderDebug(), domNode, () => handlers.done()); - handlers.onDestroy(() => ReactDOM.unmountComponentAtNode(domNode)); - }, + handlers.onDestroy(() => ReactDOM.unmountComponentAtNode(domNode)); + }, + }; + + return buttonRenderer; }; diff --git a/examples/expressions_explorer/tsconfig.json b/examples/expressions_explorer/tsconfig.json index b75817c68be7c..199dae0793f56 100644 --- a/examples/expressions_explorer/tsconfig.json +++ b/examples/expressions_explorer/tsconfig.json @@ -23,5 +23,7 @@ "@kbn/i18n-react", "@kbn/core-ui-settings-browser", "@kbn/code-editor", + "@kbn/react-kibana-context-render", + "@kbn/core-lifecycle-browser", ] } diff --git a/examples/guided_onboarding_example/kibana.jsonc b/examples/guided_onboarding_example/kibana.jsonc index 51a53dae720dd..72ee0bd46d74d 100644 --- a/examples/guided_onboarding_example/kibana.jsonc +++ b/examples/guided_onboarding_example/kibana.jsonc @@ -1,7 +1,7 @@ { "type": "plugin", "id": "@kbn/guided-onboarding-example-plugin", - "owner": "@elastic/platform-onboarding", + "owner": "@elastic/appex-sharedux", "description": "Example plugin to consume guidedOnboarding", "plugin": { "id": "guidedOnboardingExample", diff --git a/examples/response_stream/README.md b/examples/response_stream/README.md index 73c8a9161b2ce..ad3124bee805a 100644 --- a/examples/response_stream/README.md +++ b/examples/response_stream/README.md @@ -4,11 +4,15 @@ This plugin demonstrates how to stream chunks of data to the client with just a To run Kibana with the described examples, use `yarn start --run-examples`. -The `response_stream` plugin demonstrates API endpoints that can stream data chunks with a single request with gzip/compression support. gzip-streams get decompressed natively by browsers. The plugin demonstrates two use cases to get started: Streaming a raw string as well as a more complex example that streams Redux-like actions to the client which update React state via `useReducer()`. +The `response_stream` plugin demonstrates API endpoints that can stream data chunks with a single request with gzip/compression support. gzip-streams get decompressed natively by browsers. The plugin demonstrates some use cases to get you started: -Code in `@kbn/ml-response-stream` contains helpers to set up a stream on the server side (`streamFactory()`) and consume it on the client side via a custom hook (`useFetchStream()`). The utilities make use of TS generics in a way that allows to have type safety for both request related options as well as the returned data. +- Streaming just a raw string. +- Streaming NDJSON with "old-school" redux like actions and client side state managed with `useFetchStream()`. This uses React's own `useReducer()` under the hood. +- Streaming NDJSON with actions created via Redux Toolkit's `createSlice()` to a client with a full Redux Toolkit setup. -No additional third party libraries are used in the helpers to make it work. On the server, they integrate with `Hapi` and use node's own `gzip`. On the client, the custom hook abstracts away the necessary logic to consume the stream, internally it makes use of a generator function and `useReducer()` to update React state. +Code in `@kbn/ml-response-stream` contains helpers to set up a stream on the server side (`streamFactory()`) and consume it on the client side via a custom hook (`useFetchStream()`) or slice (`streamSlice()`). The utilities make use of TS generics in a way that allows to have type safety for both request related options as well as the returned data. + +Besides Redux Toolkit for its particular use case, no additional third party libraries are used in the helpers to make it work. On the server, they integrate with `Hapi` and use node's own `gzip`. On the client, the custom hook abstracts away the necessary logic to consume the stream, internally it makes use of a generator function and `useReducer()` to update React state. On the server, the simpler stream to send a string is set up like this: @@ -21,12 +25,7 @@ The request's headers get passed on to automatically identify if compression is On the client, the custom hook is used like this: ```ts -const { - errors, - start, - cancel, - data, - isRunning -} = useFetchStream('/internal/response_stream/simple_string_stream'); +const { errors, start, cancel, data, isRunning } = useFetchStream( + '/internal/response_stream/simple_string_stream' +); ``` - diff --git a/examples/response_stream/common/api/index.ts b/examples/response_stream/common/api/index.ts index 925ff844e3cfa..c5ff141e270eb 100644 --- a/examples/response_stream/common/api/index.ts +++ b/examples/response_stream/common/api/index.ts @@ -8,5 +8,6 @@ export const RESPONSE_STREAM_API_ENDPOINT = { REDUCER_STREAM: '/internal/response_stream/reducer_stream', + REDUX_STREAM: '/internal/response_stream/redux_stream', SIMPLE_STRING_STREAM: '/internal/response_stream/simple_string_stream', } as const; diff --git a/examples/response_stream/common/api/reducer_stream/index.ts b/examples/response_stream/common/api/reducer_stream/index.ts index 606834be2d0ba..cc5255761fbd6 100644 --- a/examples/response_stream/common/api/reducer_stream/index.ts +++ b/examples/response_stream/common/api/reducer_stream/index.ts @@ -9,71 +9,3 @@ export { reducerStreamReducer } from './reducer'; export { reducerStreamRequestBodySchema } from './request_body_schema'; export type { ReducerStreamRequestBodySchema } from './request_body_schema'; - -export const API_ACTION_NAME = { - UPDATE_PROGRESS: 'update_progress', - ADD_TO_ENTITY: 'add_to_entity', - DELETE_ENTITY: 'delete_entity', - ERROR: 'error', -} as const; -export type ApiActionName = typeof API_ACTION_NAME[keyof typeof API_ACTION_NAME]; - -interface ApiActionUpdateProgress { - type: typeof API_ACTION_NAME.UPDATE_PROGRESS; - payload: number; -} - -export function updateProgressAction(payload: number): ApiActionUpdateProgress { - return { - type: API_ACTION_NAME.UPDATE_PROGRESS, - payload, - }; -} - -interface ApiActionAddToEntity { - type: typeof API_ACTION_NAME.ADD_TO_ENTITY; - payload: { - entity: string; - value: number; - }; -} - -export function addToEntityAction(entity: string, value: number): ApiActionAddToEntity { - return { - type: API_ACTION_NAME.ADD_TO_ENTITY, - payload: { - entity, - value, - }, - }; -} - -interface ApiActionDeleteEntity { - type: typeof API_ACTION_NAME.DELETE_ENTITY; - payload: string; -} - -export function deleteEntityAction(payload: string): ApiActionDeleteEntity { - return { - type: API_ACTION_NAME.DELETE_ENTITY, - payload, - }; -} - -interface ApiActionError { - type: typeof API_ACTION_NAME.ERROR; - payload: string; -} - -export function errorAction(payload: string): ApiActionError { - return { - type: API_ACTION_NAME.ERROR, - payload, - }; -} - -export type ReducerStreamApiAction = - | ApiActionUpdateProgress - | ApiActionAddToEntity - | ApiActionDeleteEntity - | ApiActionError; diff --git a/examples/response_stream/common/api/reducer_stream/reducer.ts b/examples/response_stream/common/api/reducer_stream/reducer.ts index 9896e760cd75b..a793ccf55489a 100644 --- a/examples/response_stream/common/api/reducer_stream/reducer.ts +++ b/examples/response_stream/common/api/reducer_stream/reducer.ts @@ -6,24 +6,14 @@ * Side Public License, v 1. */ -import { ReducerStreamApiAction, API_ACTION_NAME } from '.'; +import { getInitialState, type StreamState } from '../stream_state'; +import { type ReducerStreamApiAction, API_ACTION_NAME } from './reducer_actions'; export const UI_ACTION_NAME = { RESET: 'reset', } as const; export type UiActionName = typeof UI_ACTION_NAME[keyof typeof UI_ACTION_NAME]; -export interface StreamState { - errors: string[]; - progress: number; - entities: Record; -} -export const initialState: StreamState = { - errors: [], - progress: 0, - entities: {}, -}; - interface UiActionResetStream { type: typeof UI_ACTION_NAME.RESET; } @@ -34,14 +24,7 @@ export function resetStream(): UiActionResetStream { type UiAction = UiActionResetStream; export type ReducerAction = ReducerStreamApiAction | UiAction; -export function reducerStreamReducer( - state: StreamState, - action: ReducerAction | ReducerAction[] -): StreamState { - if (Array.isArray(action)) { - return action.reduce(reducerStreamReducer, state); - } - +export function reducerStreamReducer(state: StreamState, action: ReducerAction): StreamState { switch (action.type) { case API_ACTION_NAME.UPDATE_PROGRESS: return { @@ -72,7 +55,7 @@ export function reducerStreamReducer( errors: [...state.errors, action.payload], }; case UI_ACTION_NAME.RESET: - return initialState; + return getInitialState(); default: return state; } diff --git a/examples/response_stream/common/api/reducer_stream/reducer_actions.ts b/examples/response_stream/common/api/reducer_stream/reducer_actions.ts new file mode 100644 index 0000000000000..7a6f077dfdfe6 --- /dev/null +++ b/examples/response_stream/common/api/reducer_stream/reducer_actions.ts @@ -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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export const API_ACTION_NAME = { + UPDATE_PROGRESS: 'update_progress', + ADD_TO_ENTITY: 'add_to_entity', + DELETE_ENTITY: 'delete_entity', + ERROR: 'error', +} as const; +export type ApiActionName = typeof API_ACTION_NAME[keyof typeof API_ACTION_NAME]; + +interface ApiActionUpdateProgress { + type: typeof API_ACTION_NAME.UPDATE_PROGRESS; + payload: number; +} + +export function updateProgressAction(payload: number): ApiActionUpdateProgress { + return { + type: API_ACTION_NAME.UPDATE_PROGRESS, + payload, + }; +} + +interface ApiActionAddToEntity { + type: typeof API_ACTION_NAME.ADD_TO_ENTITY; + payload: { + entity: string; + value: number; + }; +} + +export function addToEntityAction(entity: string, value: number): ApiActionAddToEntity { + return { + type: API_ACTION_NAME.ADD_TO_ENTITY, + payload: { + entity, + value, + }, + }; +} + +interface ApiActionDeleteEntity { + type: typeof API_ACTION_NAME.DELETE_ENTITY; + payload: string; +} + +export function deleteEntityAction(payload: string): ApiActionDeleteEntity { + return { + type: API_ACTION_NAME.DELETE_ENTITY, + payload, + }; +} + +interface ApiActionError { + type: typeof API_ACTION_NAME.ERROR; + payload: string; +} + +export function errorAction(payload: string): ApiActionError { + return { + type: API_ACTION_NAME.ERROR, + payload, + }; +} + +export type ReducerStreamApiAction = + | ApiActionUpdateProgress + | ApiActionAddToEntity + | ApiActionDeleteEntity + | ApiActionError; diff --git a/examples/response_stream/common/api/redux_stream/data_slice.ts b/examples/response_stream/common/api/redux_stream/data_slice.ts new file mode 100644 index 0000000000000..7008c5a17ddcb --- /dev/null +++ b/examples/response_stream/common/api/redux_stream/data_slice.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { createSlice } from '@reduxjs/toolkit'; +import type { PayloadAction } from '@reduxjs/toolkit'; + +import { getInitialState } from '../stream_state'; + +export const dataSlice = createSlice({ + name: 'development', + initialState: getInitialState(), + reducers: { + updateProgress: (state, action: PayloadAction) => { + state.progress = action.payload; + }, + addToEntity: ( + state, + action: PayloadAction<{ + entity: string; + value: number; + }> + ) => { + const { entity, value } = action.payload; + state.entities[entity] = (state.entities[entity] || 0) + value; + }, + deleteEntity: (state, action: PayloadAction) => { + delete state.entities[action.payload]; + }, + error: (state, action: PayloadAction) => { + state.errors.push(action.payload); + }, + reset: () => { + return getInitialState(); + }, + }, +}); + +export const { updateProgress, addToEntity, deleteEntity, error, reset } = dataSlice.actions; +export type ReduxStreamApiAction = ReturnType< + typeof dataSlice.actions[keyof typeof dataSlice.actions] +>; diff --git a/examples/response_stream/common/api/redux_stream/options_slice.ts b/examples/response_stream/common/api/redux_stream/options_slice.ts new file mode 100644 index 0000000000000..6791c74d81b33 --- /dev/null +++ b/examples/response_stream/common/api/redux_stream/options_slice.ts @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { createSlice } from '@reduxjs/toolkit'; +import type { PayloadAction } from '@reduxjs/toolkit'; + +const getInitialState = () => ({ + simulateErrors: false, + compressResponse: true, + flushFix: false, +}); + +export const optionsSlice = createSlice({ + name: 'options', + initialState: getInitialState(), + reducers: { + setSimulateErrors: (state, action: PayloadAction) => { + state.simulateErrors = action.payload; + }, + setCompressResponse: (state, action: PayloadAction) => { + state.compressResponse = action.payload; + }, + setFlushFix: (state, action: PayloadAction) => { + state.flushFix = action.payload; + }, + }, +}); + +export const { setSimulateErrors, setCompressResponse, setFlushFix } = optionsSlice.actions; +export type ReduxOptionsApiAction = ReturnType< + typeof optionsSlice.actions[keyof typeof optionsSlice.actions] +>; diff --git a/packages/kbn-unified-field-list/src/components/field_categorize_button/index.tsx b/examples/response_stream/common/api/stream_state.ts old mode 100755 new mode 100644 similarity index 61% rename from packages/kbn-unified-field-list/src/components/field_categorize_button/index.tsx rename to examples/response_stream/common/api/stream_state.ts index 8a07a8290ca84..78a541515ce8e --- a/packages/kbn-unified-field-list/src/components/field_categorize_button/index.tsx +++ b/examples/response_stream/common/api/stream_state.ts @@ -6,10 +6,14 @@ * Side Public License, v 1. */ -export { - type FieldCategorizeButtonProps, - FieldCategorizeButton, - getFieldCategorizeButton, -} from './field_categorize_button'; +export interface StreamState { + errors: string[]; + progress: number; + entities: Record; +} -export { triggerCategorizeActions, canCategorize } from './categorize_trigger_utils'; +export const getInitialState = (): StreamState => ({ + errors: [], + progress: 0, + entities: {}, +}); diff --git a/examples/response_stream/public/components/page.tsx b/examples/response_stream/public/components/page.tsx index e3138fafa71ab..2626eb317cf17 100644 --- a/examples/response_stream/public/components/page.tsx +++ b/examples/response_stream/public/components/page.tsx @@ -18,7 +18,7 @@ export const Page: FC> = ({ title = 'Untitled', chi <> -

{title}

+

{title}

{children} diff --git a/examples/response_stream/public/containers/app/components/bar_chart_race.tsx b/examples/response_stream/public/containers/app/components/bar_chart_race.tsx new file mode 100644 index 0000000000000..ef399f4cc050d --- /dev/null +++ b/examples/response_stream/public/containers/app/components/bar_chart_race.tsx @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React, { type FC } from 'react'; + +import { + Chart, + Settings, + Axis, + BarSeries, + Position, + ScaleType, + LEGACY_LIGHT_THEME, +} from '@elastic/charts'; + +interface BarChartRaceProps { + entities: Record; +} + +export const BarChartRace: FC = ({ entities }) => { + return ( +
+ + + + + + { + return { + x, + y, + }; + }) + .sort((a, b) => b.y - a.y)} + /> + +
+ ); +}; diff --git a/examples/response_stream/public/containers/app/pages/page_reducer_stream/get_status_message.tsx b/examples/response_stream/public/containers/app/components/get_status_message.tsx similarity index 100% rename from examples/response_stream/public/containers/app/pages/page_reducer_stream/get_status_message.tsx rename to examples/response_stream/public/containers/app/components/get_status_message.tsx diff --git a/examples/response_stream/public/containers/app/pages/page_reducer_stream/index.tsx b/examples/response_stream/public/containers/app/pages/page_reducer_stream/index.tsx index 7da5f68e792f8..a471d6f589034 100644 --- a/examples/response_stream/public/containers/app/pages/page_reducer_stream/index.tsx +++ b/examples/response_stream/public/containers/app/pages/page_reducer_stream/index.tsx @@ -8,16 +8,6 @@ import React, { useEffect, useState, FC } from 'react'; -import { - Chart, - Settings, - Axis, - BarSeries, - Position, - ScaleType, - LEGACY_LIGHT_THEME, -} from '@elastic/charts'; - import { EuiBadge, EuiButton, @@ -31,8 +21,8 @@ import { import { useFetchStream } from '@kbn/ml-response-stream/client'; +import { getInitialState } from '../../../../../common/api/stream_state'; import { - initialState, resetStream, reducerStreamReducer, } from '../../../../../common/api/reducer_stream/reducer'; @@ -42,7 +32,10 @@ import { Page } from '../../../../components/page'; import { useDeps } from '../../../../hooks/use_deps'; -import { getStatusMessage } from './get_status_message'; +import { BarChartRace } from '../../components/bar_chart_race'; +import { getStatusMessage } from '../../components/get_status_message'; + +const initialState = getInitialState(); export const PageReducerStream: FC = () => { const { @@ -72,8 +65,12 @@ export const PageReducerStream: FC = () => { } }; - // TODO This approach needs to be adapted as it might miss when error messages arrive bulk. - // This is for low level errors on the stream/HTTP level. + // TODO This needs to be adapted as it might miss when error messages arrive + // in bulk, but it should be good enough for this demo. This is for low level + // errors on the HTTP level.Note this will only surface errors that happen for + // the original request. Once the stream returns data, it will not be able to + // return errors. This is why we need separate error handling for application + // level errors. useEffect(() => { if (errors.length > 0) { notifications.toasts.addDanger(errors[errors.length - 1]); @@ -91,27 +88,33 @@ export const PageReducerStream: FC = () => { const buttonLabel = isRunning ? 'Stop development' : 'Start development'; return ( - +

- This demonstrates a single endpoint with streaming support that sends Redux inspired - actions from server to client. The server and client share types of the data to be - received. The client uses a custom hook that receives stream chunks and passes them on to - `useReducer()` that acts on the Redux type actions it receives. The custom hook includes - code to buffer actions and is able to apply them in bulk so the DOM does not get hammered - with updates. Hit "Start development" to trigger the bar chart race! + This demonstrates a single endpoint with streaming support that sends old school Redux + inspired actions from server to client. The server and client share types of the data to + be received. The client uses a custom hook that receives stream chunks and passes them on + to `useReducer()` that acts on the actions it receives. The custom hook includes code to + buffer actions and is able to apply them in bulk so the DOM does not get hammered with + updates. Hit "Start development" to trigger the bar chart race!


- + {buttonLabel} - {progress}% + {progress}% @@ -119,35 +122,11 @@ export const PageReducerStream: FC = () => { -
- - - - - - { - return { - x, - y, - }; - }) - .sort((a, b) => b.y - a.y)} - /> - -
+ -

{getStatusMessage(isRunning, isCancelled, data.progress)}

+

+ {getStatusMessage(isRunning, isCancelled, progress)} +

AppDispatch = useDispatch; +export const useAppSelector: TypedUseSelectorHook = useSelector; +export const useAppStore: () => AppStore = useStore; diff --git a/examples/response_stream/public/containers/app/pages/page_redux_stream/index.tsx b/examples/response_stream/public/containers/app/pages/page_redux_stream/index.tsx new file mode 100644 index 0000000000000..aaf0a7b5dbbb7 --- /dev/null +++ b/examples/response_stream/public/containers/app/pages/page_redux_stream/index.tsx @@ -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 React, { useEffect, useRef, FC } from 'react'; + +import { + EuiBadge, + EuiButton, + EuiCheckbox, + EuiFlexGroup, + EuiFlexItem, + EuiProgress, + EuiSpacer, + EuiText, +} from '@elastic/eui'; + +import { cancelStream, startStream } from '@kbn/ml-response-stream/client'; + +import { RESPONSE_STREAM_API_ENDPOINT } from '../../../../../common/api'; +import { + setSimulateErrors, + setCompressResponse, + setFlushFix, +} from '../../../../../common/api/redux_stream/options_slice'; +import { reset } from '../../../../../common/api/redux_stream/data_slice'; + +import { Page } from '../../../../components/page'; +import { useDeps } from '../../../../hooks/use_deps'; + +import { BarChartRace } from '../../components/bar_chart_race'; +import { getStatusMessage } from '../../components/get_status_message'; + +import { useAppDispatch, useAppSelector } from './hooks'; + +export const PageReduxStream: FC = () => { + const { + core: { http, notifications }, + } = useDeps(); + + const dispatch = useAppDispatch(); + const { isRunning, isCancelled, errors: streamErrors } = useAppSelector((s) => s.stream); + const { progress, entities, errors } = useAppSelector((s) => s.data); + const { simulateErrors, compressResponse, flushFix } = useAppSelector((s) => s.options); + + const abortCtrl = useRef(new AbortController()); + + const onClickHandler = async () => { + if (isRunning) { + abortCtrl.current.abort(); + dispatch(cancelStream()); + } else { + abortCtrl.current = new AbortController(); + dispatch(reset()); + dispatch( + startStream({ + http, + endpoint: RESPONSE_STREAM_API_ENDPOINT.REDUX_STREAM, + apiVersion: '1', + abortCtrl, + body: { compressResponse, flushFix, simulateErrors }, + }) + ); + } + }; + + // TODO This needs to be adapted as it might miss when error messages arrive + // in bulk, but it should be good enough for this demo. This is for low level + // errors on the HTTP level.Note this will only surface errors that happen for + // the original request. Once the stream returns data, it will not be able to + // return errors. This is why we need separate error handling for application + // level errors. + useEffect(() => { + if (streamErrors.length > 0) { + notifications.toasts.addDanger(streamErrors[streamErrors.length - 1]); + } + }, [streamErrors, notifications.toasts]); + + // TODO This approach needs to be adapted as it might miss when error messages arrive bulk. + // This is for errors on the application level + useEffect(() => { + if (errors.length > 0) { + notifications.toasts.addDanger(errors[errors.length - 1]); + } + }, [errors, notifications.toasts]); + + const buttonLabel = isRunning ? 'Stop development' : 'Start development'; + + return ( + + +

+ This demonstrates integration of a single endpoint with streaming support with Redux + Toolkit. The server and client share actions created via `createSlice`. The server sends a + stream of NDJSON data to the client where each line is a redux action. The client then + applies these actions to its state. The package `@kbn/ml-response-stream` exposes a slice + of the state that can be used to start and cancel the stream. The `startStream` action is + implemented as an async thunk that starts the stream and then dispatches received actions + to the store. Hit "Start development" to trigger the bar chart race! +

+
+
+ + + + {buttonLabel} + + + + + {progress}% + + + + + + + + + +

+ {getStatusMessage(isRunning, isCancelled, progress)} +

+ dispatch(setSimulateErrors(!simulateErrors))} + compressed + /> + dispatch(setCompressResponse(!compressResponse))} + compressed + /> + dispatch(setFlushFix(!flushFix))} + compressed + /> +
+
+ ); +}; diff --git a/examples/response_stream/public/containers/app/pages/page_redux_stream/store.tsx b/examples/response_stream/public/containers/app/pages/page_redux_stream/store.tsx new file mode 100644 index 0000000000000..ddeb265493298 --- /dev/null +++ b/examples/response_stream/public/containers/app/pages/page_redux_stream/store.tsx @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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, { type FC, type PropsWithChildren } from 'react'; +import { configureStore } from '@reduxjs/toolkit'; +import { Provider } from 'react-redux'; + +import { streamSlice } from '@kbn/ml-response-stream/client'; + +import { optionsSlice } from '../../../../../common/api/redux_stream/options_slice'; +import { dataSlice } from '../../../../../common/api/redux_stream/data_slice'; + +const reduxStore = configureStore({ + reducer: { + // State of the stream: is it running, has it errored, etc. + stream: streamSlice.reducer, + // The actual data returned by the stream. + data: dataSlice.reducer, + // Options for the stream: simulate errors, compress response, etc. + options: optionsSlice.reducer, + }, +}); + +export const ReduxStreamProvider: FC> = ({ children }) => ( + {children} +); + +// Infer the `RootState` and `AppDispatch` types from the store itself +export type AppStore = typeof reduxStore; +export type RootState = ReturnType; +export type AppDispatch = AppStore['dispatch']; diff --git a/examples/response_stream/public/containers/app/pages/page_simple_string_stream/index.tsx b/examples/response_stream/public/containers/app/pages/page_simple_string_stream/index.tsx index 7075656dc0167..3e33ade381489 100644 --- a/examples/response_stream/public/containers/app/pages/page_simple_string_stream/index.tsx +++ b/examples/response_stream/public/containers/app/pages/page_simple_string_stream/index.tsx @@ -66,7 +66,13 @@ export const PageSimpleStringStream: FC = () => {
- + {buttonLabel} @@ -81,7 +87,7 @@ export const PageSimpleStringStream: FC = () => { /> -

{data}

+

{data}

{errors.length > 0 && ( diff --git a/examples/response_stream/public/routes.tsx b/examples/response_stream/public/routes.tsx index eafe96c320d8c..f2ec595f1f753 100644 --- a/examples/response_stream/public/routes.tsx +++ b/examples/response_stream/public/routes.tsx @@ -10,6 +10,8 @@ import React from 'react'; import { PLUGIN_ID, PLUGIN_NAME } from '../common/constants'; import { PageSimpleStringStream } from './containers/app/pages/page_simple_string_stream'; import { PageReducerStream } from './containers/app/pages/page_reducer_stream'; +import { PageReduxStream } from './containers/app/pages/page_redux_stream'; +import { ReduxStreamProvider } from './containers/app/pages/page_redux_stream/store'; interface RouteSectionDef { title: string; @@ -34,10 +36,19 @@ export const routes: RouteSectionDef[] = [ component: , }, { - title: 'Reducer stream', - id: 'reducer-stream', + title: 'NDJSON useReducer stream', + id: 'ndjson-usereducer-stream', component: , }, + { + title: 'NDJSON Redux Toolkit stream', + id: 'ndjson-redux-toolkit-stream', + component: ( + + + + ), + }, ], }, ]; diff --git a/examples/response_stream/server/plugin.ts b/examples/response_stream/server/plugin.ts index 6bb0c55003059..e21c3c3f59287 100644 --- a/examples/response_stream/server/plugin.ts +++ b/examples/response_stream/server/plugin.ts @@ -9,7 +9,11 @@ import { Plugin, PluginInitializerContext, CoreSetup, CoreStart, Logger } from '@kbn/core/server'; import type { DataRequestHandlerContext } from '@kbn/data-plugin/server'; -import { defineReducerStreamRoute, defineSimpleStringStreamRoute } from './routes'; +import { + defineReducerStreamRoute, + defineReduxStreamRoute, + defineSimpleStringStreamRoute, +} from './routes'; // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface ResponseStreamSetupPlugins {} @@ -29,6 +33,7 @@ export class ResponseStreamPlugin implements Plugin { void core.getStartServices().then(([_, depsStart]) => { defineReducerStreamRoute(router, this.logger); + defineReduxStreamRoute(router, this.logger); defineSimpleStringStreamRoute(router, this.logger); }); } diff --git a/examples/response_stream/server/routes/index.ts b/examples/response_stream/server/routes/index.ts index f18a1283aa0ec..34d707ed81655 100644 --- a/examples/response_stream/server/routes/index.ts +++ b/examples/response_stream/server/routes/index.ts @@ -7,4 +7,5 @@ */ export { defineReducerStreamRoute } from './reducer_stream'; +export { defineReduxStreamRoute } from './redux_stream'; export { defineSimpleStringStreamRoute } from './single_string_stream'; diff --git a/examples/response_stream/server/routes/reducer_stream.ts b/examples/response_stream/server/routes/reducer_stream.ts index 02606b8c44756..abdc90f28a23c 100644 --- a/examples/response_stream/server/routes/reducer_stream.ts +++ b/examples/response_stream/server/routes/reducer_stream.ts @@ -11,14 +11,16 @@ import { streamFactory } from '@kbn/ml-response-stream/server'; import { errorAction, - reducerStreamRequestBodySchema, updateProgressAction, addToEntityAction, deleteEntityAction, ReducerStreamApiAction, -} from '../../common/api/reducer_stream'; +} from '../../common/api/reducer_stream/reducer_actions'; +import { reducerStreamRequestBodySchema } from '../../common/api/reducer_stream'; import { RESPONSE_STREAM_API_ENDPOINT } from '../../common/api'; +import { entities, getActions } from './shared'; + export const defineReducerStreamRoute = (router: IRouter, logger: Logger) => { router.versioned .post({ @@ -64,23 +66,7 @@ export const defineReducerStreamRoute = (router: IRouter, logger: Logger) => { request.body.flushFix ); - const entities = [ - 'kimchy', - 's1monw', - 'martijnvg', - 'jasontedor', - 'nik9000', - 'javanna', - 'rjernst', - 'jrodewig', - ]; - - const actions = [...Array(19).fill('add'), 'delete']; - - if (simulateError) { - actions.push('throw-error'); - actions.push('emit-error'); - } + const actions = getActions(simulateError); let progress = 0; @@ -101,19 +87,28 @@ export const defineReducerStreamRoute = (router: IRouter, logger: Logger) => { const randomEntity = entities[Math.floor(Math.random() * entities.length)]; const randomAction = actions[Math.floor(Math.random() * actions.length)]; - if (randomAction === 'add') { - const randomCommits = Math.floor(Math.random() * 100); - push(addToEntityAction(randomEntity, randomCommits)); - } else if (randomAction === 'delete') { - push(deleteEntityAction(randomEntity)); - } else if (randomAction === 'throw-error') { - // Throw an error. It should not crash Kibana! - // It should be caught and logged to the Kibana server console. - throw new Error('There was a (simulated) server side error!'); - } else if (randomAction === 'emit-error') { - // Emit an error as a stream action. - push(errorAction('(Simulated) error pushed to the stream')); - return; + switch (randomAction) { + case 'add': + const randomCommits = Math.floor(Math.random() * 100); + push(addToEntityAction(randomEntity, randomCommits)); + break; + + case 'delete': + push(deleteEntityAction(randomEntity)); + break; + + case 'throw-error': + // Throw an error. It should not crash Kibana! + // It should be caught and logged to the Kibana server console. + // The stream will just stop but the client will note receive an error! + // In practice this pattern should be avoided as it will just end + // the stream without an explanation. + throw new Error('There was a (simulated) server side error!'); + + case 'emit-error': + // Emit an error as a stream action. + push(errorAction('(Simulated) error pushed to the stream')); + return; } void pushStreamUpdate(); diff --git a/examples/response_stream/server/routes/redux_stream.ts b/examples/response_stream/server/routes/redux_stream.ts new file mode 100644 index 0000000000000..bd694c531907b --- /dev/null +++ b/examples/response_stream/server/routes/redux_stream.ts @@ -0,0 +1,126 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { IRouter, Logger } from '@kbn/core/server'; +import { streamFactory } from '@kbn/ml-response-stream/server'; + +import { + updateProgress, + addToEntity, + deleteEntity, + error, + type ReduxStreamApiAction, +} from '../../common/api/redux_stream/data_slice'; +import { reducerStreamRequestBodySchema } from '../../common/api/reducer_stream'; +import { RESPONSE_STREAM_API_ENDPOINT } from '../../common/api'; + +import { entities, getActions } from './shared'; + +export const defineReduxStreamRoute = (router: IRouter, logger: Logger) => { + router.versioned + .post({ + path: RESPONSE_STREAM_API_ENDPOINT.REDUX_STREAM, + access: 'internal', + }) + .addVersion( + { + version: '1', + validate: { + request: { + body: reducerStreamRequestBodySchema, + }, + }, + }, + async (context, request, response) => { + const maxTimeoutMs = request.body.timeout ?? 250; + const simulateError = request.body.simulateErrors ?? false; + + let logMessageCounter = 1; + + function logDebugMessage(msg: string) { + logger.debug(`Response Stream Example #${logMessageCounter}: ${msg}`); + logMessageCounter++; + } + + logDebugMessage('Starting stream.'); + + let shouldStop = false; + request.events.aborted$.subscribe(() => { + logDebugMessage('aborted$ subscription trigger.'); + shouldStop = true; + }); + request.events.completed$.subscribe(() => { + logDebugMessage('completed$ subscription trigger.'); + shouldStop = true; + }); + + const { end, push, responseWithHeaders } = streamFactory( + request.headers, + logger, + request.body.compressResponse, + request.body.flushFix + ); + + const actions = getActions(simulateError); + + let progress = 0; + + async function pushStreamUpdate() { + await new Promise((resolve) => + setTimeout(resolve, Math.floor(Math.random() * maxTimeoutMs)) + ); + try { + progress++; + + if (progress > 100 || shouldStop) { + end(); + return; + } + + push(updateProgress(progress)); + + const randomEntity = entities[Math.floor(Math.random() * entities.length)]; + const randomAction = actions[Math.floor(Math.random() * actions.length)]; + + switch (randomAction) { + case 'add': + const randomCommits = Math.floor(Math.random() * 100); + push(addToEntity({ entity: randomEntity, value: randomCommits })); + break; + + case 'delete': + push(deleteEntity(randomEntity)); + break; + + case 'throw-error': + // Throw an error. It should not crash Kibana! + // It should be caught and logged to the Kibana server console. + // The stream will just stop but the client will note receive an error! + // In practice this pattern should be avoided as it will just end + // the stream without an explanation. + throw new Error('There was a (simulated) server side error!'); + + case 'emit-error': + // Emit an error as a stream action. + push(error('(Simulated) error pushed to the stream')); + return; + } + + void pushStreamUpdate(); + } catch (e) { + logger.error(e); + } + } + + // do not call this using `await` so it will run asynchronously while we return the stream already. + void pushStreamUpdate(); + + return response.ok(responseWithHeaders); + } + ); +}; diff --git a/examples/response_stream/server/routes/shared.ts b/examples/response_stream/server/routes/shared.ts new file mode 100644 index 0000000000000..72223d21e09ff --- /dev/null +++ b/examples/response_stream/server/routes/shared.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export const entities = [ + 'kimchy', + 's1monw', + 'martijnvg', + 'jasontedor', + 'nik9000', + 'javanna', + 'rjernst', + 'jrodewig', +]; + +export const getActions = (simulateError: boolean) => { + const actions = [...Array(19).fill('add'), 'delete']; + + if (simulateError) { + actions.push('throw-error'); + actions.push('emit-error'); + } + + return actions; +}; diff --git a/examples/search_examples/public/application.tsx b/examples/search_examples/public/application.tsx index 10985afc4984a..9124c01b4e802 100644 --- a/examples/search_examples/public/application.tsx +++ b/examples/search_examples/public/application.tsx @@ -10,6 +10,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { Redirect } from 'react-router-dom'; import { Router, Routes, Route } from '@kbn/shared-ux-router'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import { I18nProvider } from '@kbn/i18n-react'; import { AppMountParameters, CoreStart } from '@kbn/core/public'; import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app'; @@ -44,45 +45,48 @@ export const renderApp = ( { element, history }: AppMountParameters ) => { ReactDOM.render( - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - , + + + + + + + + + , element ); diff --git a/examples/search_examples/public/search_sessions/app.tsx b/examples/search_examples/public/search_sessions/app.tsx index 7c9f28cee1026..2585b39fae814 100644 --- a/examples/search_examples/public/search_sessions/app.tsx +++ b/examples/search_examples/public/search_sessions/app.tsx @@ -30,6 +30,7 @@ import { catchError, map, tap } from 'rxjs'; import { lastValueFrom, of } from 'rxjs'; import { CoreStart } from '@kbn/core/public'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import { mountReactNode } from '@kbn/core-mount-utils-browser-internal'; import type { TimeRange } from '@kbn/es-query'; import { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public'; @@ -51,6 +52,9 @@ import { getInitialStateFromUrl, SEARCH_SESSIONS_EXAMPLES_APP_LOCATOR } from './ interface SearchSessionsExampleAppDeps { notifications: CoreStart['notifications']; + analytics: CoreStart['analytics']; + i18n: CoreStart['i18n']; + theme: CoreStart['theme']; navigation: NavigationPublicPluginStart; data: DataPublicPluginStart; unifiedSearch: UnifiedSearchPublicPluginStart; @@ -80,10 +84,10 @@ interface State extends QueryState { } export const SearchSessionsExampleApp = ({ - notifications, navigation, data, unifiedSearch, + ...startServices }: SearchSessionsExampleAppDeps) => { const { IndexPatternSelect } = unifiedSearch.ui; @@ -196,7 +200,7 @@ export const SearchSessionsExampleApp = ({ if (!numericFieldName) return; setIsSearching(true); const requestId = ++nextRequestIdRef.current; - doSearch({ dataView, numericFieldName, restoreSearchSessionId }, { data, notifications }) + doSearch({ dataView, numericFieldName, restoreSearchSessionId }, { data, ...startServices }) .then(({ response: res, request: req, tookMs: _tookMs }) => { if (requestId !== nextRequestIdRef.current) return; // no longer interested in this result if (restoreSearchSessionId) { @@ -214,7 +218,7 @@ export const SearchSessionsExampleApp = ({ setIsSearching(false); }); }, - [data, notifications, dataView, numericFieldName] + [data, dataView, numericFieldName, startServices] ); useEffect(() => { @@ -662,7 +666,14 @@ function doSearch( { data, notifications, - }: { data: DataPublicPluginStart; notifications: CoreStart['notifications'] } + ...startServices + }: { + data: DataPublicPluginStart; + notifications: CoreStart['notifications']; + analytics: CoreStart['analytics']; + i18n: CoreStart['i18n']; + theme: CoreStart['theme']; + } ): Promise<{ request: IEsSearchRequest; response: IEsSearchResponse; tookMs?: number }> { if (!dataView) return Promise.reject('Select a data view'); if (!numericFieldName) return Promise.reject('Select a field to aggregate on'); @@ -712,12 +723,14 @@ function doSearch( res.rawResponse.aggregations[1]?.value ?? res.rawResponse.aggregations[2]?.value : undefined; const message = ( - - Searched {res.rawResponse.hits.total} documents.
- The average of {numericFieldName} is {avgResult ? Math.floor(avgResult) : 0} - . -
-
+ + + Searched {res.rawResponse.hits.total} documents.
+ The average of {numericFieldName} is {avgResult ? Math.floor(avgResult) : 0} + . +
+
+
); notifications.toasts.addSuccess({ title: 'Query result', diff --git a/examples/search_examples/tsconfig.json b/examples/search_examples/tsconfig.json index 18156d4bfa198..842a75b634918 100644 --- a/examples/search_examples/tsconfig.json +++ b/examples/search_examples/tsconfig.json @@ -35,5 +35,6 @@ "@kbn/shared-ux-link-redirect-app", "@kbn/react-kibana-mount", "@kbn/search-response-warnings", + "@kbn/react-kibana-context-render", ] } diff --git a/examples/state_containers_examples/public/plugin.ts b/examples/state_containers_examples/public/plugin.ts index daf5c3216ef38..44f702ae5c8fb 100644 --- a/examples/state_containers_examples/public/plugin.ts +++ b/examples/state_containers_examples/public/plugin.ts @@ -42,6 +42,7 @@ export class StateContainersExamplesPlugin implements Plugin { const { renderApp, History } = await import('./todo/app'); const [coreStart] = await core.getStartServices(); return renderApp( + coreStart, params, { appTitle: examples.stateContainersExampleBrowserHistory.title, @@ -59,6 +60,7 @@ export class StateContainersExamplesPlugin implements Plugin { const { renderApp, History } = await import('./todo/app'); const [coreStart] = await core.getStartServices(); return renderApp( + coreStart, params, { appTitle: examples.stateContainersExampleHashHistory.title, diff --git a/examples/state_containers_examples/public/todo/app.tsx b/examples/state_containers_examples/public/todo/app.tsx index 81c067cec7d60..8c9b1266ded4b 100644 --- a/examples/state_containers_examples/public/todo/app.tsx +++ b/examples/state_containers_examples/public/todo/app.tsx @@ -6,9 +6,11 @@ * Side Public License, v 1. */ -import { AppMountParameters, CoreStart } from '@kbn/core/public'; import ReactDOM from 'react-dom'; import React from 'react'; + +import { AppMountParameters, CoreStart } from '@kbn/core/public'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import { createHashHistory } from 'history'; import { TodoAppPage } from './todo'; import { StateContainersExamplesPage, ExampleLink } from '../common/example_page'; @@ -29,15 +31,18 @@ export interface Deps { } export const renderApp = ( + core: CoreStart, { appBasePath, element, history: platformHistory }: AppMountParameters, { appTitle, historyType }: AppOptions, { navigateToApp, exampleLinks }: Deps ) => { const history = historyType === History.Browser ? platformHistory : createHashHistory(); ReactDOM.render( - - - , + + + + + , element ); diff --git a/examples/state_containers_examples/tsconfig.json b/examples/state_containers_examples/tsconfig.json index 400b8613a4d8f..cfb4e8ab9c909 100644 --- a/examples/state_containers_examples/tsconfig.json +++ b/examples/state_containers_examples/tsconfig.json @@ -23,5 +23,6 @@ "@kbn/developer-examples-plugin", "@kbn/es-query", "@kbn/shared-ux-router", + "@kbn/react-kibana-context-render", ] } diff --git a/examples/ui_actions_explorer/public/app.tsx b/examples/ui_actions_explorer/public/app.tsx index 3b5d3a99274f7..db76721f9addb 100644 --- a/examples/ui_actions_explorer/public/app.tsx +++ b/examples/ui_actions_explorer/public/app.tsx @@ -18,6 +18,7 @@ import { EuiPageHeader, } from '@elastic/eui'; import { AppMountParameters, CoreStart } from '@kbn/core/public'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import { UiActionsStart } from '@kbn/ui-actions-plugin/public'; import { TriggerContextExample } from './trigger_context_example'; import { ContextMenuExamples } from './context_menu_examples'; @@ -31,30 +32,35 @@ interface Props { const ActionsExplorer = ({ uiActionsStartService, core }: Props) => { return ( - - - - - - + + + - + + + + + - + - + - + - + - + - - - - - + + + + + + ); }; diff --git a/examples/ui_actions_explorer/tsconfig.json b/examples/ui_actions_explorer/tsconfig.json index e3070598efca1..609a609b89a50 100644 --- a/examples/ui_actions_explorer/tsconfig.json +++ b/examples/ui_actions_explorer/tsconfig.json @@ -18,5 +18,6 @@ "@kbn/ui-actions-examples-plugin", "@kbn/developer-examples-plugin", "@kbn/react-kibana-mount", + "@kbn/react-kibana-context-render", ] } diff --git a/fleet_packages.json b/fleet_packages.json index 7bbccae8a39e0..4f64dc77d5e89 100644 --- a/fleet_packages.json +++ b/fleet_packages.json @@ -30,7 +30,7 @@ }, { "name": "elastic_agent", - "version": "1.19.0" + "version": "1.19.1" }, { "name": "endpoint", diff --git a/package.json b/package.json index 04316640a2952..f4f03cb30722e 100644 --- a/package.json +++ b/package.json @@ -107,7 +107,7 @@ "@elastic/ecs": "^8.11.1", "@elastic/elasticsearch": "^8.13.0", "@elastic/ems-client": "8.5.1", - "@elastic/eui": "94.3.0", + "@elastic/eui": "94.5.1", "@elastic/filesaver": "1.1.2", "@elastic/node-crypto": "1.2.1", "@elastic/numeral": "^2.5.1", @@ -544,6 +544,7 @@ "@kbn/kibana-usage-collection-plugin": "link:src/plugins/kibana_usage_collection", "@kbn/kibana-utils-plugin": "link:src/plugins/kibana_utils", "@kbn/kubernetes-security-plugin": "link:x-pack/plugins/kubernetes_security", + "@kbn/langchain": "link:x-pack/packages/kbn-langchain", "@kbn/language-documentation-popover": "link:packages/kbn-language-documentation-popover", "@kbn/lens-config-builder-example-plugin": "link:x-pack/examples/lens_config_builder_example", "@kbn/lens-embeddable-utils": "link:packages/kbn-lens-embeddable-utils", @@ -820,7 +821,6 @@ "@kbn/slo-plugin": "link:x-pack/plugins/observability_solution/slo", "@kbn/slo-schema": "link:x-pack/packages/kbn-slo-schema", "@kbn/snapshot-restore-plugin": "link:x-pack/plugins/snapshot_restore", - "@kbn/solution-nav-es": "link:packages/solution-nav/es", "@kbn/solution-nav-oblt": "link:packages/solution-nav/oblt", "@kbn/sort-predicates": "link:packages/kbn-sort-predicates", "@kbn/spaces-plugin": "link:x-pack/plugins/spaces", @@ -998,7 +998,7 @@ "deepmerge": "^4.2.2", "del": "^6.1.0", "diff": "^5.1.0", - "elastic-apm-node": "^4.5.3", + "elastic-apm-node": "^4.5.4", "email-addresses": "^5.0.0", "eventsource-parser": "^1.1.1", "execa": "^5.1.1", diff --git a/packages/analytics/shippers/fullstory/src/fullstory_shipper.ts b/packages/analytics/shippers/fullstory/src/fullstory_shipper.ts index d02e87cace6b1..96ae3389be017 100644 --- a/packages/analytics/shippers/fullstory/src/fullstory_shipper.ts +++ b/packages/analytics/shippers/fullstory/src/fullstory_shipper.ts @@ -30,7 +30,7 @@ const PAGE_VARS_KEYS = [ // Deployment-specific keys 'version', // x4, split to version_major, version_minor, version_patch for easier filtering - 'buildNum', // May be useful for Serverless, TODO: replace with buildHash + 'buildSha', // Useful for Serverless 'cloudId', 'deploymentId', 'projectId', // projectId and deploymentId are mutually exclusive. They shouldn't be sent in the same offering. diff --git a/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.test.tsx b/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.test.tsx index 08847884eeafe..de0ff6dd95c76 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.test.tsx +++ b/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.test.tsx @@ -21,7 +21,10 @@ import { notificationServiceMock } from '@kbn/core-notifications-browser-mocks'; import { uiSettingsServiceMock } from '@kbn/core-ui-settings-browser-mocks'; import { customBrandingServiceMock } from '@kbn/core-custom-branding-browser-mocks'; import { analyticsServiceMock } from '@kbn/core-analytics-browser-mocks'; +import { i18nServiceMock } from '@kbn/core-i18n-browser-mocks'; +import { themeServiceMock } from '@kbn/core-theme-browser-mocks'; import { getAppInfo } from '@kbn/core-application-browser-internal'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import { findTestSubject } from '@kbn/test-jest-helpers'; import { ChromeService } from './chrome_service'; @@ -48,6 +51,9 @@ Object.defineProperty(window, 'localStorage', { function defaultStartDeps(availableApps?: App[], currentAppId?: string) { const deps = { + analytics: analyticsServiceMock.createAnalyticsServiceStart(), + i18n: i18nServiceMock.createStartContract(), + theme: themeServiceMock.createStartContract(), application: applicationServiceMock.createInternalStartContract(currentAppId), docLinks: docLinksServiceMock.createStartContract(), http: httpServiceMock.createStartContract(), @@ -94,7 +100,7 @@ async function start({ startDeps.injectedMetadata.getCspConfig.mockReturnValue(cspConfigMock); } - await service.setup({ analytics: analyticsServiceMock.createAnalyticsServiceSetup() }); + service.setup({ analytics: analyticsServiceMock.createAnalyticsServiceSetup() }); const chromeStart = await service.start(startDeps); return { @@ -118,7 +124,7 @@ describe('setup', () => { it('calls registerAnalyticsContextProvider with the correct parameters', async () => { const service = new ChromeService(defaultStartTestOptions({})); const analytics = analyticsServiceMock.createAnalyticsServiceSetup(); - await service.setup({ analytics }); + service.setup({ analytics }); expect(registerAnalyticsContextProviderMock).toHaveBeenCalledTimes(1); expect(registerAnalyticsContextProviderMock).toHaveBeenCalledWith( @@ -206,7 +212,7 @@ describe('start', () => { }); it('renders the custom project side navigation', async () => { - const { chrome } = await start({ + const { chrome, startDeps } = await start({ startDeps: defaultStartDeps([{ id: 'foo', title: 'Foo' } as App], 'foo'), }); @@ -216,7 +222,11 @@ describe('start', () => { chrome.setChromeStyle('project'); chrome.project.setSideNavComponent(MyNav); - const component = mount(chrome.getHeaderComponent()); + const component = mount( + + {chrome.getHeaderComponent()} + + ); const projectHeader = findTestSubject(component, 'kibanaProjectHeader'); expect(projectHeader.length).toBe(1); @@ -229,11 +239,15 @@ describe('start', () => { }); it('renders chromeless header', async () => { - const { chrome } = await start({ startDeps: defaultStartDeps() }); + const { chrome, startDeps } = await start({ startDeps: defaultStartDeps() }); chrome.setIsVisible(false); - const component = mount(chrome.getHeaderComponent()); + const component = mount( + + {chrome.getHeaderComponent()} + + ); const chromeless = findTestSubject(component, 'kibanaHeaderChromeless'); expect(chromeless.length).toBe(1); @@ -418,7 +432,7 @@ describe('start', () => { const promise = chrome.getBreadcrumbsAppendExtension$().pipe(toArray()).toPromise(); chrome.setBreadcrumbsAppendExtension({ - content: (element) => () => {}, + content: () => () => {}, }); service.stop(); diff --git a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/breadcrumbs.tsx b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/breadcrumbs.tsx index ed23d25434664..694007921537f 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/breadcrumbs.tsx +++ b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/breadcrumbs.tsx @@ -40,7 +40,7 @@ export function buildBreadcrumbs({ activeNodes: ChromeProjectNavigationNode[][]; solutionNavigations?: { definitions: SolutionNavigationDefinitions; - activeId: string; + activeId: string | null; onChange: (id: string) => void; }; }): ChromeProjectBreadcrumb[] { @@ -106,7 +106,7 @@ function buildRootCrumb({ cloudLinks: CloudLinks; solutionNavigations?: { definitions: SolutionNavigationDefinitions; - activeId: string; + activeId: string | null; onChange: (id: string) => void; }; }): ChromeProjectBreadcrumb { diff --git a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.test.ts b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.test.ts index 71fac1455031b..312290683f63f 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.test.ts +++ b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.test.ts @@ -328,6 +328,7 @@ describe('initNavigation()', () => { "href": "/app/discover", "id": "discover", "isElasticInternalLink": false, + "onClick": undefined, "path": "rootNav:analytics.discover", "sideNavStatus": "visible", "title": "DISCOVER", @@ -346,6 +347,7 @@ describe('initNavigation()', () => { "href": "/app/dashboards", "id": "dashboards", "isElasticInternalLink": false, + "onClick": undefined, "path": "rootNav:analytics.dashboards", "sideNavStatus": "visible", "title": "DASHBOARDS", @@ -364,6 +366,7 @@ describe('initNavigation()', () => { "href": "/app/visualize", "id": "visualize", "isElasticInternalLink": false, + "onClick": undefined, "path": "rootNav:analytics.visualize", "sideNavStatus": "visible", "title": "VISUALIZE", @@ -374,6 +377,7 @@ describe('initNavigation()', () => { "icon": "stats", "id": "rootNav:analytics", "isElasticInternalLink": false, + "onClick": undefined, "path": "rootNav:analytics", "renderAs": "accordion", "sideNavStatus": "visible", diff --git a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.ts b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.ts index ddd00cea5b37e..f07ac64de3856 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.ts +++ b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.ts @@ -162,6 +162,7 @@ export class ProjectNavigationService { chromeBreadcrumbs$, this.projectName$, this.solutionNavDefinitions$, + this.nextSolutionNavDefinitionId$, this.activeSolutionNavDefinitionId$, this.cloudLinks$, ]).pipe( @@ -172,12 +173,13 @@ export class ProjectNavigationService { chromeBreadcrumbs, projectName, solutionNavDefinitions, + nextSolutionNavDefinitionId, activeSolutionNavDefinitionId, cloudLinks, ]) => { const solutionNavigations = Object.keys(solutionNavDefinitions).length > 0 && - activeSolutionNavDefinitionId !== null + (nextSolutionNavDefinitionId !== null || activeSolutionNavDefinitionId !== null) ? { definitions: solutionNavDefinitions, activeId: activeSolutionNavDefinitionId, diff --git a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.ts b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.ts index cbc199bbca51e..6e84ab54c11f1 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.ts +++ b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.ts @@ -23,6 +23,7 @@ import type { ItemDefinition, } from '@kbn/core-chrome-browser/src'; import type { Location } from 'history'; +import type { MouseEventHandler } from 'react'; import { getPresets } from './navigation_presets'; const wrapIdx = (index: number): string => `[${index}]`; @@ -212,15 +213,17 @@ function getNodeStatus( deepLink, cloudLink, sideNavStatus, + onClick, }: { link?: string; deepLink?: ChromeNavLink; cloudLink?: CloudLinkId; sideNavStatus?: SideNavNodeStatus; + onClick?: MouseEventHandler; }, { cloudLinks }: { cloudLinks: CloudLinks } ): SideNavNodeStatus | 'remove' { - if (link && !deepLink) { + if (link && !deepLink && !onClick) { // If a link is provided, but no deepLink is found, don't render anything return 'remove'; } @@ -259,7 +262,7 @@ function validateNodeProps< LinkId extends AppDeepLinkId = AppDeepLinkId, Id extends string = string, ChildrenId extends string = Id ->({ id, link, href, cloudLink, renderAs }: NodeDefinition) { +>({ id, link, href, cloudLink, renderAs, onClick }: NodeDefinition) { if (link && cloudLink) { throw new Error( `[Chrome navigation] Error in node [${id}]. Only one of "link" or "cloudLink" can be provided.` @@ -275,9 +278,9 @@ function validateNodeProps< `[Chrome navigation] Error in node [${id}]. If renderAs is set to "panelOpener", a "link" must also be provided.` ); } - if (renderAs === 'item' && !link) { + if (renderAs === 'item' && !link && !onClick) { throw new Error( - `[Chrome navigation] Error in node [${id}]. If renderAs is set to "item", a "link" must also be provided.` + `[Chrome navigation] Error in node [${id}]. If renderAs is set to "item", a "link" or "onClick" must also be provided.` ); } } @@ -302,7 +305,7 @@ const initNavNode = < ): ChromeProjectNavigationNode | null => { validateNodeProps(node); - const { cloudLink, link, children, ...navNodeFromProps } = node; + const { cloudLink, link, children, onClick, ...navNodeFromProps } = node; const deepLink = link !== undefined ? deepLinks[link] : undefined; const sideNavStatus = getNodeStatus( { @@ -310,6 +313,7 @@ const initNavNode = < deepLink, cloudLink, sideNavStatus: navNodeFromProps.sideNavStatus, + onClick, }, { cloudLinks } ); @@ -324,7 +328,7 @@ const initNavNode = < const href = isElasticInternalLink ? cloudLinks[cloudLink]?.href : node.href; const path = parentNodePath ? `${parentNodePath}.${id}` : id; - if (href && !isAbsoluteLink(href)) { + if (href && !isAbsoluteLink(href) && !onClick) { throw new Error(`href must be an absolute URL. Node id [${id}].`); } @@ -332,6 +336,7 @@ const initNavNode = < ...navNodeFromProps, id, href: getNavigationNodeHref({ href, deepLink }), + onClick, path, title, deepLink, diff --git a/packages/core/chrome/core-chrome-browser-internal/src/ui/solution_nav_switcher_breadcrumbs.tsx b/packages/core/chrome/core-chrome-browser-internal/src/ui/solution_nav_switcher_breadcrumbs.tsx index abb617e988724..b6cc812b9a23c 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/ui/solution_nav_switcher_breadcrumbs.tsx +++ b/packages/core/chrome/core-chrome-browser-internal/src/ui/solution_nav_switcher_breadcrumbs.tsx @@ -21,7 +21,7 @@ export const getSolutionNavSwitcherBreadCrumb = ({ cloudLinks, }: { definitions: SolutionNavigationDefinitions; - activeId: string; + activeId: string | null; onChange: (id: string) => void; cloudLinks: CloudLinks; }): ChromeProjectBreadcrumb => { diff --git a/packages/core/chrome/core-chrome-browser-internal/tsconfig.json b/packages/core/chrome/core-chrome-browser-internal/tsconfig.json index ceb3cd525a19d..5d81526f2c970 100644 --- a/packages/core/chrome/core-chrome-browser-internal/tsconfig.json +++ b/packages/core/chrome/core-chrome-browser-internal/tsconfig.json @@ -52,6 +52,9 @@ "@kbn/core-base-browser-mocks", "@kbn/logging", "@kbn/logging-mocks", + "@kbn/core-i18n-browser-mocks", + "@kbn/core-theme-browser-mocks", + "@kbn/react-kibana-context-render", ], "exclude": [ "target/**/*", diff --git a/packages/core/chrome/core-chrome-browser/index.ts b/packages/core/chrome/core-chrome-browser/index.ts index 431e83db04afa..27c20f502bc06 100644 --- a/packages/core/chrome/core-chrome-browser/index.ts +++ b/packages/core/chrome/core-chrome-browser/index.ts @@ -56,4 +56,5 @@ export type { NavigationTreeDefinitionUI, SolutionNavigationDefinition, SolutionNavigationDefinitions, + EuiSideNavItemTypeEnhanced, } from './src'; diff --git a/packages/core/chrome/core-chrome-browser/src/index.ts b/packages/core/chrome/core-chrome-browser/src/index.ts index 4c0ca3f12a506..a287499cd73ff 100644 --- a/packages/core/chrome/core-chrome-browser/src/index.ts +++ b/packages/core/chrome/core-chrome-browser/src/index.ts @@ -55,4 +55,5 @@ export type { NavigationTreeDefinitionUI, SolutionNavigationDefinition, SolutionNavigationDefinitions, + EuiSideNavItemTypeEnhanced, } from './project_navigation'; 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 b198b88b52839..75f3b3be8edce 100644 --- a/packages/core/chrome/core-chrome-browser/src/project_navigation.ts +++ b/packages/core/chrome/core-chrome-browser/src/project_navigation.ts @@ -6,9 +6,9 @@ * Side Public License, v 1. */ -import type { ComponentType } from 'react'; +import type { ComponentType, MouseEventHandler } from 'react'; import type { Location } from 'history'; -import type { EuiThemeSizes, IconType } from '@elastic/eui'; +import type { EuiSideNavItemType, EuiThemeSizes, IconType } from '@elastic/eui'; import type { Observable } from 'rxjs'; import type { AppId as DevToolsApp, DeepLinkId as DevToolsLink } from '@kbn/deeplinks-devtools'; import type { @@ -128,6 +128,10 @@ interface NodeDefinitionBase { * href for absolute links only. Internal links should use "link". */ href?: string; + /** + * Custom handler to execute when clicking on the node. This handler takes precedence over the "link" or "href" props. + */ + onClick?: MouseEventHandler; /** * Optional status to indicate if the breadcrumb should be hidden when this node is active. * @default 'visible' @@ -434,3 +438,15 @@ export interface SolutionNavigationDefinition = Omit, 'items'> & { + items?: Array>; + iconToString?: string; + nameToString?: string; +}; diff --git a/packages/core/http/core-http-router-server-internal/src/request.test.ts b/packages/core/http/core-http-router-server-internal/src/request.test.ts index 72d81e9ce48e6..f895cb0e2fde7 100644 --- a/packages/core/http/core-http-router-server-internal/src/request.test.ts +++ b/packages/core/http/core-http-router-server-internal/src/request.test.ts @@ -201,6 +201,36 @@ describe('CoreKibanaRequest', () => { }); }); + describe('route.httpVersion property', () => { + it('returns the version from the raw request', () => { + const request = hapiMocks.createRequest({ + raw: { + req: { + httpVersion: '7.4', + }, + }, + }); + const kibanaRequest = CoreKibanaRequest.from(request); + + expect(kibanaRequest.httpVersion).toEqual('7.4'); + }); + }); + + describe('route.protocol property', () => { + it('return a static value for now as only http1 is supported', () => { + const request = hapiMocks.createRequest({ + raw: { + req: { + httpVersion: '2.0', + }, + }, + }); + const kibanaRequest = CoreKibanaRequest.from(request); + + expect(kibanaRequest.protocol).toEqual('http1'); + }); + }); + describe('route.options.authRequired property', () => { it('handles required auth: undefined', () => { const auth: RouteOptions['auth'] = undefined; @@ -370,6 +400,17 @@ describe('CoreKibanaRequest', () => { }); }); + describe('httpVersion', () => { + it('should be 1.0', () => { + const request: FakeRawRequest = { + headers: {}, + path: '/', + }; + const kibanaRequest = CoreKibanaRequest.from(request); + expect(kibanaRequest.httpVersion).toEqual('1.0'); + }); + }); + describe('headers', () => { it('returns the correct headers', () => { const request: FakeRawRequest = { diff --git a/packages/core/http/core-http-router-server-internal/src/request.ts b/packages/core/http/core-http-router-server-internal/src/request.ts index 450294fb09c0f..d3274b0a2a1fe 100644 --- a/packages/core/http/core-http-router-server-internal/src/request.ts +++ b/packages/core/http/core-http-router-server-internal/src/request.ts @@ -29,6 +29,7 @@ import { KibanaRequestRouteOptions, RawRequest, FakeRawRequest, + HttpProtocol, } from '@kbn/core-http-server'; import { ELASTIC_INTERNAL_ORIGIN_QUERY_PARAM, @@ -131,6 +132,10 @@ export class CoreKibanaRequest< public readonly isInternalApiRequest: boolean; /** {@inheritDoc KibanaRequest.rewrittenUrl} */ public readonly rewrittenUrl?: URL; + /** {@inheritDoc KibanaRequest.httpVersion} */ + public readonly httpVersion: string; + /** {@inheritDoc KibanaRequest.protocol} */ + public readonly protocol: HttpProtocol; /** @internal */ protected readonly [requestSymbol]!: Request; @@ -167,6 +172,10 @@ export class CoreKibanaRequest< enumerable: false, }); + this.httpVersion = isRealReq ? request.raw.req.httpVersion : '1.0'; + // hardcoded for now as only supporting http1 + this.protocol = 'http1'; + this.route = deepFreeze(this.getRouteInfo(request)); this.socket = isRealReq ? new KibanaSocket(request.raw.req.socket) diff --git a/packages/core/http/core-http-server-internal/src/http_server.ts b/packages/core/http/core-http-server-internal/src/http_server.ts index 236b9567ddcb7..478d1d746bbac 100644 --- a/packages/core/http/core-http-server-internal/src/http_server.ts +++ b/packages/core/http/core-http-server-internal/src/http_server.ts @@ -10,14 +10,7 @@ import { Server, Request } from '@hapi/hapi'; import HapiStaticFiles from '@hapi/inert'; import url from 'url'; import { v4 as uuidv4 } from 'uuid'; -import { - createServer, - getListenerOptions, - getServerOptions, - setTlsConfig, - getRequestId, -} from '@kbn/server-http-tools'; - +import { createServer, getServerOptions, setTlsConfig, getRequestId } from '@kbn/server-http-tools'; import type { Duration } from 'moment'; import { Observable, Subscription, firstValueFrom, pairwise, take } from 'rxjs'; import apm from 'elastic-apm-node'; @@ -235,9 +228,8 @@ export class HttpServer { this.config = config; const serverOptions = getServerOptions(config); - const listenerOptions = getListenerOptions(config); - this.server = createServer(serverOptions, listenerOptions); + this.server = createServer(serverOptions); await this.server.register([HapiStaticFiles]); if (config.compression.brotli.enabled) { await this.server.register({ diff --git a/packages/core/http/core-http-server-internal/src/https_redirect_server.ts b/packages/core/http/core-http-server-internal/src/https_redirect_server.ts index 501c83377fe0a..2999c4aaf734e 100644 --- a/packages/core/http/core-http-server-internal/src/https_redirect_server.ts +++ b/packages/core/http/core-http-server-internal/src/https_redirect_server.ts @@ -8,7 +8,7 @@ import { Request, ResponseToolkit, Server } from '@hapi/hapi'; import { format as formatUrl } from 'url'; -import { createServer, getListenerOptions, getServerOptions } from '@kbn/server-http-tools'; +import { createServer, getServerOptions } from '@kbn/server-http-tools'; import type { Logger } from '@kbn/logging'; import { HttpConfig } from './http_config'; @@ -31,13 +31,10 @@ export class HttpsRedirectServer { // Redirect server is configured in the same way as any other HTTP server // within the platform with the only exception that it should always be a // plain HTTP server, so we just ignore `tls` part of options. - this.server = createServer( - { - ...getServerOptions(config, { configureTLS: false }), - port: config.ssl.redirectHttpFromPort, - }, - getListenerOptions(config) - ); + this.server = createServer({ + ...getServerOptions(config, { configureTLS: false }), + port: config.ssl.redirectHttpFromPort, + }); this.server.ext('onRequest', (request: Request, responseToolkit: ResponseToolkit) => { return responseToolkit diff --git a/packages/core/http/core-http-server/index.ts b/packages/core/http/core-http-server/index.ts index 859e6ff8efbd5..2b288be521d3a 100644 --- a/packages/core/http/core-http-server/index.ts +++ b/packages/core/http/core-http-server/index.ts @@ -141,6 +141,7 @@ export type { HttpServicePreboot, HttpServiceSetup, HttpServiceStart, + HttpProtocol, } from './src/http_contract'; export type { diff --git a/packages/core/http/core-http-server/src/http_contract.ts b/packages/core/http/core-http-server/src/http_contract.ts index 09250abf8adae..308ba2dd48785 100644 --- a/packages/core/http/core-http-server/src/http_contract.ts +++ b/packages/core/http/core-http-server/src/http_contract.ts @@ -402,3 +402,11 @@ export interface HttpServerInfo { /** The protocol used by the server */ protocol: 'http' | 'https' | 'socket'; } + +/** + * Defines an http protocol. + * (Only supporting http1 for now) + * + * - http1: regroups all http/1.x protocols + */ +export type HttpProtocol = 'http1'; diff --git a/packages/core/http/core-http-server/src/router/request.ts b/packages/core/http/core-http-server/src/router/request.ts index e1242dee7eb67..a58c97ccee762 100644 --- a/packages/core/http/core-http-server/src/router/request.ts +++ b/packages/core/http/core-http-server/src/router/request.ts @@ -10,6 +10,7 @@ import type { URL } from 'url'; import type { RequestApplicationState, RouteOptionsApp } from '@hapi/hapi'; import type { Observable } from 'rxjs'; import type { RecursiveReadonly } from '@kbn/utility-types'; +import type { HttpProtocol } from '../http_contract'; import type { IKibanaSocket } from './socket'; import type { RouteMethod, RouteConfigOptions } from './route'; import type { Headers } from './headers'; @@ -141,6 +142,16 @@ export interface KibanaRequest< */ readonly isInternalApiRequest: boolean; + /** + * The HTTP version sent by the client. + */ + readonly httpVersion: string; + + /** + * The protocol used by the client, inferred from the httpVersion. + */ + readonly protocol: HttpProtocol; + /** * The socket associated with this request. * See {@link IKibanaSocket}. diff --git a/packages/core/i18n/core-i18n-browser-internal/src/__snapshots__/i18n_service.test.tsx.snap b/packages/core/i18n/core-i18n-browser-internal/src/__snapshots__/i18n_service.test.tsx.snap index 29a42c3a4c654..fd8ba14e035cf 100644 --- a/packages/core/i18n/core-i18n-browser-internal/src/__snapshots__/i18n_service.test.tsx.snap +++ b/packages/core/i18n/core-i18n-browser-internal/src/__snapshots__/i18n_service.test.tsx.snap @@ -6,8 +6,8 @@ exports[`#start() returns \`Context\` component 1`] = ` i18n={ Object { "mapping": Object { + "euiAbsoluteTab.dateFormatButtonLabel": "Parse date", "euiAbsoluteTab.dateFormatError": [Function], - "euiAbsoluteTab.dateFormatHint": "Press the Enter key to parse as a date.", "euiAccordionChildrenLoading.message": "Loading", "euiAutoRefresh.autoRefreshLabel": "Auto refresh", "euiAutoRefresh.buttonLabelOff": "Auto refresh is off", @@ -36,6 +36,7 @@ exports[`#start() returns \`Context\` component 1`] = ` "euiCodeBlockFullScreen.fullscreenExpand": "Expand", "euiCollapsedItemActions.allActions": "All actions", "euiCollapsedItemActions.allActionsDisabled": "Individual item actions are disabled when rows are being selected.", + "euiCollapsedNavButton.ariaLabelButtonIcon": [Function], "euiCollapsibleNavBeta.ariaLabel": "Site menu", "euiCollapsibleNavButton.ariaLabelClose": "Close navigation", "euiCollapsibleNavButton.ariaLabelCollapse": "Collapse navigation", diff --git a/packages/core/i18n/core-i18n-browser-internal/src/i18n_eui_mapping.tsx b/packages/core/i18n/core-i18n-browser-internal/src/i18n_eui_mapping.tsx index c7d290f3af603..386e7a55da83b 100644 --- a/packages/core/i18n/core-i18n-browser-internal/src/i18n_eui_mapping.tsx +++ b/packages/core/i18n/core-i18n-browser-internal/src/i18n_eui_mapping.tsx @@ -179,6 +179,11 @@ export const getEuiContextMapping = (): EuiTokensObject => { 'euiCollapsibleNavBeta.ariaLabel': i18n.translate('core.euiCollapsibleNavBeta.ariaLabel', { defaultMessage: 'Site menu', }), + 'euiCollapsedNavButton.ariaLabelButtonIcon': ({ title }: EuiValues) => + i18n.translate('core.euiCollapsedNavButton.ariaLabelButtonIcon', { + defaultMessage: '{title}, quick navigation menu', + values: { title }, + }), 'euiCollapsibleNavButton.ariaLabelExpand': i18n.translate( 'core.euiCollapsibleNavButton.ariaLabelExpand', { defaultMessage: 'Expand navigation' } @@ -1413,9 +1418,12 @@ export const getEuiContextMapping = (): EuiTokensObject => { 'euiRelativeTab.dateInputError': i18n.translate('core.euiRelativeTab.dateInputError', { defaultMessage: 'Must be a valid range', }), - 'euiAbsoluteTab.dateFormatHint': i18n.translate('core.euiAbsoluteTab.dateFormatHint', { - defaultMessage: 'Press the Enter key to parse as a date.', - }), + 'euiAbsoluteTab.dateFormatButtonLabel': i18n.translate( + 'core.euiAbsoluteTab.dateFormatButtonLabel', + { + defaultMessage: 'Parse date', + } + ), 'euiResizableButton.horizontalResizerAriaLabel': i18n.translate( 'core.euiResizableButton.horizontalResizerAriaLabel', { diff --git a/packages/core/saved-objects/core-saved-objects-base-server-internal/src/constants.ts b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/constants.ts index 4244a5fed91aa..becc08d872f91 100644 --- a/packages/core/saved-objects/core-saved-objects-base-server-internal/src/constants.ts +++ b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/constants.ts @@ -185,7 +185,7 @@ export const HASH_TO_VERSION_MAP = { 'ingest-agent-policies|0fd93cd11c019b118e93a9157c22057b': '10.1.0', 'ingest-download-sources|0b0f6828e59805bd07a650d80817c342': '10.0.0', 'ingest-outputs|b1237f7fdc0967709e75d65d208ace05': '10.6.0', - 'ingest-package-policies|a1a074bad36e68d54f98d2158d60f879': '10.0.0', + 'ingest-package-policies|aef7977b81f7930f23cbfd8711ba272e': '10.9.0', 'inventory-view|3d1b76c39bfb2cc8296b024d73854724': '10.0.0', 'kql-telemetry|3d1b76c39bfb2cc8296b024d73854724': '10.0.0', 'legacy-url-alias|0750774cf16475f88f2361e99cc5c8f0': '8.2.0', diff --git a/packages/core/status/core-status-server-internal/src/routes/status_response_schemas.ts b/packages/core/status/core-status-server-internal/src/routes/status_response_schemas.ts index 36671f2089bb2..236e279ef27fe 100644 --- a/packages/core/status/core-status-server-internal/src/routes/status_response_schemas.ts +++ b/packages/core/status/core-status-server-internal/src/routes/status_response_schemas.ts @@ -146,7 +146,7 @@ const fullStatusResponse: () => Type> = () => }, { meta: { - id: 'core.status.response', + id: 'core_status_response', description: `Kibana's operational status as well as a detailed breakdown of plugin statuses indication of various loads (like event loop utilization and network traffic) at time of request.`, }, } @@ -163,7 +163,7 @@ const redactedStatusResponse = () => }, { meta: { - id: 'core.status.redactedResponse', + id: 'core_status_redactedResponse', description: `A minimal representation of Kibana's operational status.`, }, } diff --git a/packages/kbn-check-mappings-update-cli/current_fields.json b/packages/kbn-check-mappings-update-cli/current_fields.json index 04343968ef958..ad653171f2707 100644 --- a/packages/kbn-check-mappings-update-cli/current_fields.json +++ b/packages/kbn-check-mappings-update-cli/current_fields.json @@ -602,6 +602,7 @@ "overrides", "package", "package.name", + "package.requires_root", "package.title", "package.version", "policy_id", diff --git a/packages/kbn-check-mappings-update-cli/current_mappings.json b/packages/kbn-check-mappings-update-cli/current_mappings.json index 6ee1f6d13521f..6d54282cabafe 100644 --- a/packages/kbn-check-mappings-update-cli/current_mappings.json +++ b/packages/kbn-check-mappings-update-cli/current_mappings.json @@ -2017,6 +2017,9 @@ "name": { "type": "keyword" }, + "requires_root": { + "type": "boolean" + }, "title": { "type": "keyword" }, diff --git a/packages/kbn-cli-dev-mode/src/base_path_proxy_server.ts b/packages/kbn-cli-dev-mode/src/base_path_proxy_server.ts index 46cd67e1e0642..f9aaad7923152 100644 --- a/packages/kbn-cli-dev-mode/src/base_path_proxy_server.ts +++ b/packages/kbn-cli-dev-mode/src/base_path_proxy_server.ts @@ -15,7 +15,7 @@ import { sampleSize } from 'lodash'; import * as Rx from 'rxjs'; import { take } from 'rxjs'; import { ByteSizeValue } from '@kbn/config-schema'; -import { createServer, getListenerOptions, getServerOptions } from '@kbn/server-http-tools'; +import { createServer, getServerOptions } from '@kbn/server-http-tools'; import { DevConfig, HttpConfig } from './config'; import { Log } from './log'; @@ -67,8 +67,7 @@ export class BasePathProxyServer { public async start(options: BasePathProxyServerOptions) { const serverOptions = getServerOptions(this.httpConfig); - const listenerOptions = getListenerOptions(this.httpConfig); - this.server = createServer(serverOptions, listenerOptions); + this.server = createServer(serverOptions); // Register hapi plugin that adds proxying functionality. It can be configured // through the route configuration object (see { handler: { proxy: ... } }). diff --git a/packages/kbn-cli-dev-mode/src/integration_tests/base_path_proxy_server.test.ts b/packages/kbn-cli-dev-mode/src/integration_tests/base_path_proxy_server.test.ts index 0f0a69638cfa2..432f67a75f1b0 100644 --- a/packages/kbn-cli-dev-mode/src/integration_tests/base_path_proxy_server.test.ts +++ b/packages/kbn-cli-dev-mode/src/integration_tests/base_path_proxy_server.test.ts @@ -10,12 +10,7 @@ import { Server } from '@hapi/hapi'; import { EMPTY } from 'rxjs'; import moment from 'moment'; import supertest from 'supertest'; -import { - getServerOptions, - getListenerOptions, - createServer, - IHttpConfig, -} from '@kbn/server-http-tools'; +import { getServerOptions, createServer, type IHttpConfig } from '@kbn/server-http-tools'; import { ByteSizeValue } from '@kbn/config-schema'; import { BasePathProxyServer, BasePathProxyServerOptions } from '../base_path_proxy_server'; @@ -51,8 +46,7 @@ describe('BasePathProxyServer', () => { }; const serverOptions = getServerOptions(config); - const listenerOptions = getListenerOptions(config); - server = createServer(serverOptions, listenerOptions); + server = createServer(serverOptions); // setup and start the proxy server const proxyConfig: IHttpConfig = { ...config, port: 10013 }; @@ -276,8 +270,7 @@ describe('BasePathProxyServer', () => { } as IHttpConfig; const serverOptions = getServerOptions(configWithBasePath); - const listenerOptions = getListenerOptions(configWithBasePath); - server = createServer(serverOptions, listenerOptions); + server = createServer(serverOptions); server.route({ method: 'GET', diff --git a/packages/kbn-config-schema/index.ts b/packages/kbn-config-schema/index.ts index 0ab1fd640d7af..c6ef8c2ce99dc 100644 --- a/packages/kbn-config-schema/index.ts +++ b/packages/kbn-config-schema/index.ts @@ -49,6 +49,7 @@ import { URIType, StreamType, UnionTypeOptions, + Lazy, } from './src/types'; export type { AnyType, ConditionalType, TypeOf, Props, SchemaStructureEntry, NullableProps }; @@ -216,6 +217,13 @@ function conditional
( return new ConditionalType(leftOperand, rightOperand, equalType, notEqualType, options); } +/** + * Useful for creating recursive schemas. + */ +function lazy(id: string) { + return new Lazy(id); +} + export const schema = { any, arrayOf, @@ -226,6 +234,7 @@ export const schema = { contextRef, duration, ip, + lazy, literal, mapOf, maybe, @@ -245,7 +254,6 @@ export type Schema = typeof schema; import { META_FIELD_X_OAS_ANY, - META_FIELD_X_OAS_REF_ID, META_FIELD_X_OAS_OPTIONAL, META_FIELD_X_OAS_DEPRECATED, META_FIELD_X_OAS_MAX_LENGTH, @@ -255,7 +263,6 @@ import { export const metaFields = Object.freeze({ META_FIELD_X_OAS_ANY, - META_FIELD_X_OAS_REF_ID, META_FIELD_X_OAS_OPTIONAL, META_FIELD_X_OAS_DEPRECATED, META_FIELD_X_OAS_MAX_LENGTH, diff --git a/packages/kbn-config-schema/src/oas_meta_fields.ts b/packages/kbn-config-schema/src/oas_meta_fields.ts index 814bb32e7ea41..d1846be8ecf14 100644 --- a/packages/kbn-config-schema/src/oas_meta_fields.ts +++ b/packages/kbn-config-schema/src/oas_meta_fields.ts @@ -15,6 +15,5 @@ export const META_FIELD_X_OAS_MIN_LENGTH = 'x-oas-min-length' as const; export const META_FIELD_X_OAS_MAX_LENGTH = 'x-oas-max-length' as const; export const META_FIELD_X_OAS_GET_ADDITIONAL_PROPERTIES = 'x-oas-get-additional-properties' as const; -export const META_FIELD_X_OAS_REF_ID = 'x-oas-ref-id' as const; export const META_FIELD_X_OAS_DEPRECATED = 'x-oas-deprecated' as const; export const META_FIELD_X_OAS_ANY = 'x-oas-any-type' as const; diff --git a/packages/kbn-config-schema/src/types/index.ts b/packages/kbn-config-schema/src/types/index.ts index e3d8db0b2302d..78eab0957557d 100644 --- a/packages/kbn-config-schema/src/types/index.ts +++ b/packages/kbn-config-schema/src/types/index.ts @@ -40,3 +40,4 @@ export { URIType } from './uri_type'; export { NeverType } from './never_type'; export type { IpOptions } from './ip_type'; export { IpType } from './ip_type'; +export { Lazy } from './lazy'; diff --git a/packages/kbn-config-schema/src/types/lazy.test.ts b/packages/kbn-config-schema/src/types/lazy.test.ts new file mode 100644 index 0000000000000..52864a9c825a8 --- /dev/null +++ b/packages/kbn-config-schema/src/types/lazy.test.ts @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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, schema } from '../..'; + +interface RecursiveType { + name: string; + self: undefined | RecursiveType; +} + +// Test our recursive type inference +{ + const id = 'recursive'; + // @ts-expect-error + const testObject: Type = schema.object( + { + name: schema.string(), + notSelf: schema.lazy(id), // this declaration should fail + }, + { meta: { id } } + ); +} + +describe('lazy', () => { + const id = 'recursive'; + const object = schema.object( + { + name: schema.string(), + self: schema.lazy(id), + }, + { meta: { id } } + ); + + it('allows recursive runtime types to be defined', () => { + const self: RecursiveType = { + name: 'self1', + self: { + name: 'self2', + self: { + name: 'self3', + self: { + name: 'self4', + self: undefined, + }, + }, + }, + }; + const { value, error } = object.getSchema().validate(self); + expect(error).toBeUndefined(); + expect(value).toEqual(self); + }); + + it('detects invalid recursive types as expected', () => { + const invalidSelf = { + name: 'self1', + self: { + name: 123, + self: undefined, + }, + }; + + const { error, value } = object.getSchema().validate(invalidSelf); + expect(value).toEqual(invalidSelf); + expect(error?.message).toBe('expected value of type [string] but got [number]'); + }); +}); diff --git a/packages/kbn-config-schema/src/types/lazy.ts b/packages/kbn-config-schema/src/types/lazy.ts new file mode 100644 index 0000000000000..28dda1b701394 --- /dev/null +++ b/packages/kbn-config-schema/src/types/lazy.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 } from './type'; +import { internals } from '../internals'; + +/** + * Use this type to construct recursive runtime schemas. + */ +export class Lazy extends Type { + constructor(id: string) { + super(internals.link(`#${id}`)); + } +} diff --git a/packages/kbn-config-schema/src/types/object_type.test.ts b/packages/kbn-config-schema/src/types/object_type.test.ts index 12ed554e11099..bf92d22615504 100644 --- a/packages/kbn-config-schema/src/types/object_type.test.ts +++ b/packages/kbn-config-schema/src/types/object_type.test.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import { get } from 'lodash'; import { expectType } from 'tsd'; import { schema } from '../..'; import { TypeOf } from './object_type'; @@ -21,6 +22,16 @@ test('returns value by default', () => { expect(type.validate(value)).toEqual({ name: 'test' }); }); +test('meta', () => { + const type = schema.object( + { + name: schema.string(), + }, + { meta: { id: 'test_id' } } + ); + expect(get(type.getSchema().describe(), 'flags.id')).toEqual('test_id'); +}); + test('returns empty object if undefined', () => { const type = schema.object({}); expect(type.validate(undefined)).toEqual({}); diff --git a/packages/kbn-config-schema/src/types/object_type.ts b/packages/kbn-config-schema/src/types/object_type.ts index 702d6d100847e..d5193b5e0fc38 100644 --- a/packages/kbn-config-schema/src/types/object_type.ts +++ b/packages/kbn-config-schema/src/types/object_type.ts @@ -69,8 +69,16 @@ interface UnknownOptions { unknowns?: OptionsForUnknowns; } +interface ObjectTypeOptionsMeta { + /** + * A string that uniquely identifies this schema. Used when generating OAS + * to create refs instead of inline schemas. + */ + id?: string; +} + export type ObjectTypeOptions

= TypeOptions> & - UnknownOptions; + UnknownOptions & { meta?: TypeOptions>['meta'] & ObjectTypeOptionsMeta }; export class ObjectType

extends Type> { private props: P; @@ -83,7 +91,7 @@ export class ObjectType

extends Type> for (const [key, value] of Object.entries(props)) { schemaKeys[key] = value.getSchema(); } - const schema = internals + let schema = internals .object() .keys(schemaKeys) .default() @@ -91,6 +99,10 @@ export class ObjectType

extends Type> .unknown(unknowns === 'allow') .options({ stripUnknown: { objects: unknowns === 'ignore' } }); + if (options.meta?.id) { + schema = schema.id(options.meta.id); + } + super(schema, typeOptions); this.props = props; this.propSchemas = schemaKeys; diff --git a/packages/kbn-config-schema/src/types/type.test.ts b/packages/kbn-config-schema/src/types/type.test.ts index a4784af2e8b62..a0ca8603d46f0 100644 --- a/packages/kbn-config-schema/src/types/type.test.ts +++ b/packages/kbn-config-schema/src/types/type.test.ts @@ -9,7 +9,7 @@ import { get } from 'lodash'; import { internals } from '../internals'; import { Type, TypeOptions } from './type'; -import { META_FIELD_X_OAS_REF_ID, META_FIELD_X_OAS_DEPRECATED } from '../oas_meta_fields'; +import { META_FIELD_X_OAS_DEPRECATED } from '../oas_meta_fields'; class MyType extends Type { constructor(opts: TypeOptions = {}) { @@ -20,12 +20,11 @@ class MyType extends Type { describe('meta', () => { it('sets meta when provided', () => { const type = new MyType({ - meta: { description: 'my description', id: 'foo', deprecated: true }, + meta: { description: 'my description', deprecated: true }, }); const meta = type.getSchema().describe(); expect(get(meta, 'flags.description')).toBe('my description'); - expect(get(meta, `metas[0].${META_FIELD_X_OAS_REF_ID}`)).toBe('foo'); - expect(get(meta, `metas[1].${META_FIELD_X_OAS_DEPRECATED}`)).toBe(true); + expect(get(meta, `metas[0].${META_FIELD_X_OAS_DEPRECATED}`)).toBe(true); }); it('does not set meta when no provided', () => { diff --git a/packages/kbn-config-schema/src/types/type.ts b/packages/kbn-config-schema/src/types/type.ts index 80ed3f90fdd2a..652eae077d5af 100644 --- a/packages/kbn-config-schema/src/types/type.ts +++ b/packages/kbn-config-schema/src/types/type.ts @@ -7,7 +7,7 @@ */ import type { AnySchema, CustomValidator, ErrorReport } from 'joi'; -import { META_FIELD_X_OAS_DEPRECATED, META_FIELD_X_OAS_REF_ID } from '../oas_meta_fields'; +import { META_FIELD_X_OAS_DEPRECATED } from '../oas_meta_fields'; import { SchemaTypeError, ValidationError } from '../errors'; import { Reference } from '../references'; @@ -24,11 +24,6 @@ export interface TypeMeta { * Whether this field is deprecated. */ deprecated?: boolean; - /** - * A string that uniquely identifies this schema. Used when generating OAS - * to create refs instead of inline schemas. - */ - id?: string; } export interface TypeOptions { @@ -112,9 +107,6 @@ export abstract class Type { if (options.meta.description) { schema = schema.description(options.meta.description); } - if (options.meta.id) { - schema = schema.meta({ [META_FIELD_X_OAS_REF_ID]: options.meta.id }); - } if (options.meta.deprecated) { schema = schema.meta({ [META_FIELD_X_OAS_DEPRECATED]: true }); } diff --git a/packages/kbn-doc-links/src/get_doc_links.ts b/packages/kbn-doc-links/src/get_doc_links.ts index 68bd793b3d5c9..a599f9a2bf0b6 100644 --- a/packages/kbn-doc-links/src/get_doc_links.ts +++ b/packages/kbn-doc-links/src/get_doc_links.ts @@ -858,6 +858,7 @@ export const getDocLinks = ({ kibanaBranch, buildFlavor }: GetDocLinkOptions): D remoteESOoutput: `${FLEET_DOCS}monitor-elastic-agent.html#external-elasticsearch-monitoring`, performancePresets: `${FLEET_DOCS}es-output-settings.html#es-output-settings-performance-tuning-settings`, scalingKubernetesResourcesAndLimits: `${FLEET_DOCS}scaling-on-kubernetes.html#_specifying_resources_and_limits_in_agent_manifests`, + roleAndPrivileges: `${FLEET_DOCS}fleet-roles-and-privileges.html`, }, ecs: { guide: `${ELASTIC_WEBSITE_URL}guide/en/ecs/${ECS_VERSION}/index.html`, diff --git a/packages/kbn-doc-links/src/types.ts b/packages/kbn-doc-links/src/types.ts index fb59c867cff9d..567652df3123c 100644 --- a/packages/kbn-doc-links/src/types.ts +++ b/packages/kbn-doc-links/src/types.ts @@ -551,6 +551,7 @@ export interface DocLinks { remoteESOoutput: string; performancePresets: string; scalingKubernetesResourcesAndLimits: string; + roleAndPrivileges: string; }>; readonly ecs: { readonly guide: string; diff --git a/packages/kbn-es-query/index.ts b/packages/kbn-es-query/index.ts index 3793f0efb8855..943d3dc28f570 100644 --- a/packages/kbn-es-query/index.ts +++ b/packages/kbn-es-query/index.ts @@ -9,6 +9,7 @@ export type { BoolQuery, DataViewBase, + DataViewBaseNoFields, DataViewFieldBase, EsQueryConfig, EsQueryFiltersConfig, @@ -117,6 +118,8 @@ export { toElasticsearchQuery, escapeKuery, escapeQuotes, + getKqlFieldNames, + getKqlFieldNamesFromExpression, } from './src/kuery'; export { diff --git a/packages/kbn-es-query/src/es_query/index.ts b/packages/kbn-es-query/src/es_query/index.ts index bb84ddbc16f97..ba11fd2fc3581 100644 --- a/packages/kbn-es-query/src/es_query/index.ts +++ b/packages/kbn-es-query/src/es_query/index.ts @@ -24,6 +24,7 @@ export type { IFieldSubType, BoolQuery, DataViewBase, + DataViewBaseNoFields, DataViewFieldBase, IFieldSubTypeMulti, IFieldSubTypeNested, diff --git a/packages/kbn-es-query/src/es_query/types.ts b/packages/kbn-es-query/src/es_query/types.ts index 89c22521a6409..1a756f55cf145 100644 --- a/packages/kbn-es-query/src/es_query/types.ts +++ b/packages/kbn-es-query/src/es_query/types.ts @@ -64,12 +64,14 @@ export type DataViewFieldBase = { * A base interface for an index pattern * @public */ -// eslint-disable-next-line @typescript-eslint/consistent-type-definitions -export type DataViewBase = { +export interface DataViewBase extends DataViewBaseNoFields { fields: DataViewFieldBase[]; +} + +export interface DataViewBaseNoFields { id?: string; title: string; -}; +} export interface BoolQuery { must: estypes.QueryDslQueryContainer[]; diff --git a/packages/kbn-es-query/src/filters/build_filters/build_filters.ts b/packages/kbn-es-query/src/filters/build_filters/build_filters.ts index 368c9e779f8e3..7719e922374ca 100644 --- a/packages/kbn-es-query/src/filters/build_filters/build_filters.ts +++ b/packages/kbn-es-query/src/filters/build_filters/build_filters.ts @@ -14,7 +14,7 @@ import { buildPhrasesFilter } from './phrases_filter'; import { buildRangeFilter, RangeFilterParams } from './range_filter'; import { buildExistsFilter } from './exists_filter'; -import type { DataViewFieldBase, DataViewBase } from '../../es_query'; +import type { DataViewFieldBase, DataViewBase, DataViewBaseNoFields } from '../../es_query'; import { FilterStateStore } from './types'; /** @@ -52,7 +52,7 @@ export function buildFilter( } function buildBaseFilter( - indexPattern: DataViewBase, + indexPattern: DataViewBaseNoFields, field: DataViewFieldBase, type: FILTERS, params: Serializable diff --git a/packages/kbn-es-query/src/filters/build_filters/exists_filter.ts b/packages/kbn-es-query/src/filters/build_filters/exists_filter.ts index 23210093fc8a8..bb28f7f786cd1 100644 --- a/packages/kbn-es-query/src/filters/build_filters/exists_filter.ts +++ b/packages/kbn-es-query/src/filters/build_filters/exists_filter.ts @@ -7,7 +7,7 @@ */ import { has } from 'lodash'; -import type { DataViewFieldBase, DataViewBase } from '../../es_query'; +import type { DataViewFieldBase, DataViewBaseNoFields } from '../../es_query'; import type { Filter, FilterMeta } from './types'; /** @public */ @@ -44,7 +44,7 @@ export const getExistsFilterField = (filter: ExistsFilter) => { * * @public */ -export const buildExistsFilter = (field: DataViewFieldBase, indexPattern: DataViewBase) => { +export const buildExistsFilter = (field: DataViewFieldBase, indexPattern: DataViewBaseNoFields) => { return { meta: { index: indexPattern.id, diff --git a/packages/kbn-es-query/src/filters/build_filters/phrase_filter.ts b/packages/kbn-es-query/src/filters/build_filters/phrase_filter.ts index 0b990bd9cdfa7..485a10fddb038 100644 --- a/packages/kbn-es-query/src/filters/build_filters/phrase_filter.ts +++ b/packages/kbn-es-query/src/filters/build_filters/phrase_filter.ts @@ -9,7 +9,7 @@ import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { SerializableRecord } from '@kbn/utility-types'; import { get, has, isPlainObject } from 'lodash'; import type { Filter, FilterMeta } from './types'; -import type { DataViewFieldBase, DataViewBase } from '../../es_query'; +import type { DataViewFieldBase, DataViewBaseNoFields } from '../../es_query'; import { getConvertedValueForField } from './get_converted_value_for_field'; import { hasRangeKeys } from './range_filter'; @@ -101,7 +101,7 @@ export const getPhraseFilterValue = ( export const buildPhraseFilter = ( field: DataViewFieldBase, value: PhraseFilterValue, - indexPattern: DataViewBase + indexPattern: DataViewBaseNoFields ): PhraseFilter | ScriptedPhraseFilter => { const convertedValue = getConvertedValueForField(field, value); diff --git a/packages/kbn-es-query/src/filters/build_filters/phrases_filter.ts b/packages/kbn-es-query/src/filters/build_filters/phrases_filter.ts index 2e2b954012867..09027a821da5d 100644 --- a/packages/kbn-es-query/src/filters/build_filters/phrases_filter.ts +++ b/packages/kbn-es-query/src/filters/build_filters/phrases_filter.ts @@ -9,7 +9,7 @@ import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { Filter, FilterMeta, FILTERS } from './types'; import { getPhraseScript, PhraseFilterValue } from './phrase_filter'; -import type { DataViewFieldBase, DataViewBase } from '../../es_query'; +import type { DataViewFieldBase, DataViewBaseNoFields } from '../../es_query'; export type PhrasesFilterMeta = FilterMeta & { params: PhraseFilterValue[]; // The unformatted values @@ -50,7 +50,7 @@ export const getPhrasesFilterField = (filter: PhrasesFilter) => { export const buildPhrasesFilter = ( field: DataViewFieldBase, params: PhraseFilterValue[], - indexPattern: DataViewBase + indexPattern: DataViewBaseNoFields ) => { const index = indexPattern.id; const type = FILTERS.PHRASES; diff --git a/packages/kbn-es-query/src/filters/build_filters/range_filter.ts b/packages/kbn-es-query/src/filters/build_filters/range_filter.ts index b1b0fdb0590ab..f80fce31cb8ae 100644 --- a/packages/kbn-es-query/src/filters/build_filters/range_filter.ts +++ b/packages/kbn-es-query/src/filters/build_filters/range_filter.ts @@ -10,7 +10,7 @@ import { map, reduce, mapValues, has, get, keys, pickBy } from 'lodash'; import type { SerializableRecord } from '@kbn/utility-types'; import type { Filter, FilterMeta, FilterMetaParams } from './types'; import { FILTERS } from './types'; -import type { DataViewBase, DataViewFieldBase } from '../../es_query'; +import type { DataViewFieldBase, DataViewBaseNoFields } from '../../es_query'; const OPERANDS_IN_RANGE = 2; @@ -133,7 +133,7 @@ const formatValue = (params: any[]) => * * @param field * @param params - * @param indexPattern + * @param dataView * @param formattedValue * @returns * @@ -142,7 +142,7 @@ const formatValue = (params: any[]) => export const buildRangeFilter = ( field: DataViewFieldBase, params: RangeFilterParams, - indexPattern?: DataViewBase, + indexPattern?: DataViewBaseNoFields, formattedValue?: string ): RangeFilter | ScriptedRangeFilter | MatchAllRangeFilter => { params = mapValues(params, (value: any) => (field.type === 'number' ? parseFloat(value) : value)); diff --git a/packages/kbn-es-query/src/kuery/index.ts b/packages/kbn-es-query/src/kuery/index.ts index 002c67b19c7dc..3e1576bc576e9 100644 --- a/packages/kbn-es-query/src/kuery/index.ts +++ b/packages/kbn-es-query/src/kuery/index.ts @@ -23,5 +23,10 @@ export const toElasticsearchQuery = (...params: Parameters { + it('returns single kuery field', () => { + const expression = 'service.name: my-service'; + expect(getKqlFieldNamesFromExpression(expression)).toEqual(['service.name']); + }); + + it('returns kuery fields with wildcard', () => { + const expression = 'service.name: *'; + expect(getKqlFieldNamesFromExpression(expression)).toEqual(['service.name']); + }); + + it('returns multiple fields used AND operator', () => { + const expression = 'service.name: my-service AND service.environment: production'; + expect(getKqlFieldNamesFromExpression(expression)).toEqual([ + 'service.name', + 'service.environment', + ]); + }); + + it('returns multiple kuery fields with OR operator', () => { + const expression = 'network.carrier.mcc: test or child.id: 33'; + expect(getKqlFieldNamesFromExpression(expression)).toEqual(['network.carrier.mcc', 'child.id']); + }); + + it('returns multiple kuery fields with wildcard', () => { + const expression = 'network.carrier.mcc:* or child.id: *'; + expect(getKqlFieldNamesFromExpression(expression)).toEqual(['network.carrier.mcc', 'child.id']); + }); + + it('returns single kuery fields with gt operator', () => { + const expression = 'transaction.duration.aggregate > 10'; + expect(getKqlFieldNamesFromExpression(expression)).toEqual(['transaction.duration.aggregate']); + }); + + it('returns duplicate fields', () => { + const expression = 'service.name: my-service and service.name: my-service and trace.id: trace'; + expect(getKqlFieldNamesFromExpression(expression)).toEqual([ + 'service.name', + 'service.name', + 'trace.id', + ]); + }); + + it('returns multiple fields with multiple logical operators', () => { + const expression = + '(service.name:opbeans-* OR service.name:kibana) and (service.environment:production)'; + expect(getKqlFieldNamesFromExpression(expression)).toEqual([ + 'service.name', + 'service.name', + 'service.environment', + ]); + }); + + it('returns nested fields', () => { + const expression = 'user.names:{ first: "Alice" and last: "White" }'; + expect(getKqlFieldNamesFromExpression(expression)).toEqual(['user.names']); + }); + + it('returns wildcard fields', () => { + const expression = 'server.*: kibana'; + expect(getKqlFieldNamesFromExpression(expression)).toEqual(['server.*']); + }); + + // _field_caps doesn't allow escaped wildcards, so for now this behavior is what we want + it('returns escaped fields', () => { + const expression = 'server.\\*: kibana'; + expect(getKqlFieldNamesFromExpression(expression)).toEqual(['server.*']); + }); + + it('do not return if kuery field is null', () => { + const expression = 'opbean'; + expect(getKqlFieldNamesFromExpression(expression)).toEqual([]); + }); +}); diff --git a/packages/kbn-es-query/src/kuery/utils/get_kql_fields.ts b/packages/kbn-es-query/src/kuery/utils/get_kql_fields.ts new file mode 100644 index 0000000000000..7cef22b3f89c7 --- /dev/null +++ b/packages/kbn-es-query/src/kuery/utils/get_kql_fields.ts @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { fromKueryExpression, KueryNode } from '../../..'; +import { nodeTypes } from '../node_types'; +import { functions } from '../functions'; + +export function getKqlFieldNamesFromExpression(expression: string): string[] { + const node = fromKueryExpression(expression); + return getKqlFieldNames(node); +} + +export function getKqlFieldNames(node: KueryNode): string[] { + if (nodeTypes.function.isNode(node)) { + if (functions.and.isNode(node) || functions.or.isNode(node)) { + return node.arguments.reduce((result, child) => { + return result.concat(getKqlFieldNames(child)); + }, []); + } else if ( + functions.not.isNode(node) || + functions.exists.isNode(node) || + functions.is.isNode(node) || + functions.nested.isNode(node) || + functions.range.isNode(node) + ) { + // For each of these field types, we only need to look at the first argument to determine the fields + const [fieldNode] = node.arguments; + return getKqlFieldNames(fieldNode); + } else { + throw new Error(`KQL function ${node.function} not supported in getKqlFieldNames`); + } + } else if (nodeTypes.literal.isNode(node)) { + if (node.value === null) return []; + return [`${nodeTypes.literal.toElasticsearchQuery(node)}`]; + } else if (nodeTypes.wildcard.isNode(node)) { + return [nodeTypes.wildcard.toElasticsearchQuery(node)]; + } else { + throw new Error(`KQL node type ${node.type} not supported in getKqlFieldNames`); + } +} diff --git a/packages/kbn-es-query/src/kuery/utils/index.ts b/packages/kbn-es-query/src/kuery/utils/index.ts index 8726b56a466cc..31e19c713fc0d 100644 --- a/packages/kbn-es-query/src/kuery/utils/index.ts +++ b/packages/kbn-es-query/src/kuery/utils/index.ts @@ -7,3 +7,4 @@ */ export { escapeKuery, escapeQuotes } from './escape_kuery'; +export { getKqlFieldNames, getKqlFieldNamesFromExpression } from './get_kql_fields'; diff --git a/packages/kbn-es/src/serverless_resources/project_roles/security/roles.yml b/packages/kbn-es/src/serverless_resources/project_roles/security/roles.yml index def2ff2cdeb55..5d70bb0044fc5 100644 --- a/packages/kbn-es/src/serverless_resources/project_roles/security/roles.yml +++ b/packages/kbn-es/src/serverless_resources/project_roles/security/roles.yml @@ -468,6 +468,7 @@ soc_manager: - feature_siem.actions_log_management_all - feature_siem.file_operations_all - feature_siem.execute_operations_all + - feature_siem.scan_operations_all - feature_securitySolutionCases.all - feature_securitySolutionAssistant.all - feature_actions.all @@ -644,9 +645,10 @@ endpoint_operations_analyst: - feature_siem.blocklist_all - feature_siem.host_isolation_all - feature_siem.process_operations_all - - feature_siem.actions_log_management_all # Response History + - feature_siem.actions_log_management_all - feature_siem.file_operations_all - - feature_siem.execute_operations_all # Execute + - feature_siem.execute_operations_all + - feature_siem.scan_operations_all - feature_securitySolutionCases.all - feature_securitySolutionAssistant.all - feature_actions.all diff --git a/packages/kbn-es/src/utils/docker.test.ts b/packages/kbn-es/src/utils/docker.test.ts index ec706a64a96ac..b3e7bd30ad83e 100644 --- a/packages/kbn-es/src/utils/docker.test.ts +++ b/packages/kbn-es/src/utils/docker.test.ts @@ -438,7 +438,6 @@ describe('resolveEsArgs()', () => { kibanaUrl: 'https://localhost:5601/', }); - expect(esArgs).toHaveLength(26); expect(esArgs).toMatchInlineSnapshot(` Array [ "--env", @@ -448,6 +447,8 @@ describe('resolveEsArgs()', () => { "--env", "xpack.security.http.ssl.verification_mode=certificate", "--env", + "xpack.security.authc.native_role_mappings.enabled=true", + "--env", "xpack.security.authc.realms.saml.cloud-saml-kibana.order=0", "--env", "xpack.security.authc.realms.saml.cloud-saml-kibana.idp.metadata.path=/usr/share/elasticsearch/config/secrets/idp_metadata.xml", @@ -477,7 +478,6 @@ describe('resolveEsArgs()', () => { kibanaUrl: 'https://localhost:5601/', }); - expect(esArgs).toHaveLength(8); expect(esArgs).toMatchInlineSnapshot(` Array [ "--env", diff --git a/packages/kbn-es/src/utils/docker.ts b/packages/kbn-es/src/utils/docker.ts index b0795a70f7d72..60232c97897d2 100644 --- a/packages/kbn-es/src/utils/docker.ts +++ b/packages/kbn-es/src/utils/docker.ts @@ -486,6 +486,10 @@ export function resolveEsArgs( ) { const trimTrailingSlash = (url: string) => (url.endsWith('/') ? url.slice(0, -1) : url); + // The mock IDP setup requires a custom role mapping, but since native role mappings are disabled by default in + // Serverless, we have to re-enable them explicitly here. + esArgs.set('xpack.security.authc.native_role_mappings.enabled', 'true'); + esArgs.set(`xpack.security.authc.realms.saml.${MOCK_IDP_REALM_NAME}.order`, '0'); esArgs.set( `xpack.security.authc.realms.saml.${MOCK_IDP_REALM_NAME}.idp.metadata.path`, diff --git a/packages/kbn-guided-onboarding/kibana.jsonc b/packages/kbn-guided-onboarding/kibana.jsonc index 6f9768ce87ce3..6b7815910f2f5 100644 --- a/packages/kbn-guided-onboarding/kibana.jsonc +++ b/packages/kbn-guided-onboarding/kibana.jsonc @@ -1,5 +1,5 @@ { "type": "shared-common", "id": "@kbn/guided-onboarding", - "owner": "@elastic/platform-onboarding" + "owner": "@elastic/appex-sharedux" } diff --git a/packages/kbn-hapi-mocks/src/request.ts b/packages/kbn-hapi-mocks/src/request.ts index 511e580071954..4379fcb9aeef0 100644 --- a/packages/kbn-hapi-mocks/src/request.ts +++ b/packages/kbn-hapi-mocks/src/request.ts @@ -39,6 +39,7 @@ export const createRequestMock = (customization: DeepPartial = {}): Req req: { url: path, socket: {}, + httpVersion: '1.1', }, res: { addListener: jest.fn(), diff --git a/packages/kbn-health-gateway-server/src/server/server.test.mocks.ts b/packages/kbn-health-gateway-server/src/server/server.test.mocks.ts index 543fe9b29e9cc..657b1fc26b930 100644 --- a/packages/kbn-health-gateway-server/src/server/server.test.mocks.ts +++ b/packages/kbn-health-gateway-server/src/server/server.test.mocks.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { sslSchema, getServerOptions, getListenerOptions } from '@kbn/server-http-tools'; +import { sslSchema, getServerOptions } from '@kbn/server-http-tools'; export const hapiStartMock = jest.fn(); export const hapiStopMock = jest.fn(); @@ -18,12 +18,10 @@ export const createServerMock = jest.fn().mockImplementation(() => ({ route: hapiRouteMock, })); export const getServerOptionsMock = jest.fn().mockImplementation(getServerOptions); -export const getListenerOptionsMock = jest.fn().mockImplementation(getListenerOptions); jest.doMock('@kbn/server-http-tools', () => ({ createServer: createServerMock, getServerOptions: getServerOptionsMock, - getListenerOptions: getListenerOptionsMock, sslSchema, SslConfig: jest.fn(), })); diff --git a/packages/kbn-health-gateway-server/src/server/server.test.ts b/packages/kbn-health-gateway-server/src/server/server.test.ts index e0a65229c3374..739bb8f0a5916 100644 --- a/packages/kbn-health-gateway-server/src/server/server.test.ts +++ b/packages/kbn-health-gateway-server/src/server/server.test.ts @@ -9,7 +9,6 @@ import { createServerMock, getServerOptionsMock, - getListenerOptionsMock, hapiStartMock, hapiStopMock, hapiRouteMock, @@ -56,9 +55,6 @@ describe('Server', () => { expect(getServerOptionsMock.mock.calls[0][0]).toEqual( expect.objectContaining({ ...mockConfig }) ); - expect(getListenerOptionsMock.mock.calls[0][0]).toEqual( - expect.objectContaining({ ...mockConfig }) - ); }); test('starts the Hapi server', async () => { diff --git a/packages/kbn-health-gateway-server/src/server/server.ts b/packages/kbn-health-gateway-server/src/server/server.ts index e75df33859981..1b679db5b9085 100644 --- a/packages/kbn-health-gateway-server/src/server/server.ts +++ b/packages/kbn-health-gateway-server/src/server/server.ts @@ -7,7 +7,7 @@ */ import type { Server as HapiServer, ServerRoute as HapiServerRoute } from '@hapi/hapi'; -import { createServer, getServerOptions, getListenerOptions } from '@kbn/server-http-tools'; +import { createServer, getServerOptions } from '@kbn/server-http-tools'; import type { IConfigService } from '@kbn/config'; import type { Logger, LoggerFactory } from '@kbn/logging'; import { ServerConfig } from './server_config'; @@ -40,7 +40,7 @@ export class Server { async start(): Promise { const serverConfig = new ServerConfig(this.config.atPathSync('server')); - this.server = createServer(getServerOptions(serverConfig), getListenerOptions(serverConfig)); + this.server = createServer(getServerOptions(serverConfig)); await this.server.start(); this.log.info(`Server running on ${this.server.info.uri}`); diff --git a/packages/kbn-reporting/common/constants.ts b/packages/kbn-reporting/common/constants.ts index 4620b46e8cab6..e041291323439 100644 --- a/packages/kbn-reporting/common/constants.ts +++ b/packages/kbn-reporting/common/constants.ts @@ -55,6 +55,7 @@ export const REPORTING_MANAGEMENT_HOME = '/app/management/insightsAndAlerting/re * ILM */ +// The ILM policy manages stored reports only in stateful deployments. export const ILM_POLICY_NAME = 'kibana-reporting'; /* diff --git a/packages/kbn-reporting/common/types.ts b/packages/kbn-reporting/common/types.ts index 92eb444880543..39d5a79e731c6 100644 --- a/packages/kbn-reporting/common/types.ts +++ b/packages/kbn-reporting/common/types.ts @@ -149,6 +149,7 @@ export interface ReportSource { migration_version: string; // for reminding the user to update their POST URL attempts: number; // initially populated as 0 created_at: string; // timestamp in UTC + '@timestamp'?: string; // creation timestamp, only used for data streams compatibility status: JOB_STATUS; /* diff --git a/packages/kbn-reporting/common/url.ts b/packages/kbn-reporting/common/url.ts index 14772b3a612aa..d7140bbd22044 100644 --- a/packages/kbn-reporting/common/url.ts +++ b/packages/kbn-reporting/common/url.ts @@ -29,12 +29,6 @@ export interface LocatorParams

{ describe('@kbn/config-schema', () => { it('generates the expected OpenAPI document', () => { @@ -30,8 +35,8 @@ describe('generateOpenApiDocument', () => { }); it('generates references in the expected format', () => { - const sharedIdSchema = schema.string({ minLength: 1, meta: { id: 'my.id' } }); - const sharedNameSchema = schema.string({ minLength: 1, meta: { id: 'my.name' } }); + const sharedIdSchema = schema.string({ minLength: 1, meta: { description: 'test' } }); + const sharedNameSchema = schema.string({ minLength: 1 }); const otherSchema = schema.object({ name: sharedNameSchema, other: schema.string() }); expect( generateOpenApiDocument( @@ -70,6 +75,52 @@ describe('generateOpenApiDocument', () => { ) ).toMatchSnapshot(); }); + + it('handles recursive schemas', () => { + const id = 'recursive'; + const recursiveSchema: Type = schema.object( + { + name: schema.string(), + self: schema.lazy(id), + }, + { meta: { id } } + ); + expect( + generateOpenApiDocument( + { + routers: [ + createRouter({ + routes: [ + { + isVersioned: false, + path: '/recursive', + method: 'get', + validationSchemas: { + request: { + body: recursiveSchema, + }, + response: { + [200]: { + body: () => schema.string({ maxLength: 10, minLength: 1 }), + }, + }, + }, + options: { tags: ['foo'] }, + handler: jest.fn(), + }, + ], + }), + ], + versionedRouters: [], + }, + { + title: 'test', + baseUrl: 'https://test.oas', + version: '99.99.99', + } + ) + ).toMatchSnapshot(); + }); }); describe('unknown schema/validation', () => { diff --git a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/lib.test.ts b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/lib.test.ts index 5933605768378..9e43b45ddc64c 100644 --- a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/lib.test.ts +++ b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/lib.test.ts @@ -6,11 +6,8 @@ * Side Public License, v 1. */ -import { schema, metaFields } from '@kbn/config-schema'; -import { set } from '@kbn/safer-lodash-set'; -import { omit } from 'lodash'; -import { OpenAPIV3 } from 'openapi-types'; -import { is, tryConvertToRef, isNullableObjectType } from './lib'; +import { schema } from '@kbn/config-schema'; +import { is, isNullableObjectType } from './lib'; describe('is', () => { test.each([ @@ -34,27 +31,6 @@ describe('is', () => { }); }); -test('tryConvertToRef', () => { - const schemaObject: OpenAPIV3.SchemaObject = { - type: 'object', - properties: { - a: { - type: 'string', - }, - }, - }; - set(schemaObject, metaFields.META_FIELD_X_OAS_REF_ID, 'foo'); - expect(tryConvertToRef(schemaObject)).toEqual({ - idSchema: ['foo', { type: 'object', properties: { a: { type: 'string' } } }], - ref: { - $ref: '#/components/schemas/foo', - }, - }); - - const schemaObject2 = omit(schemaObject, metaFields.META_FIELD_X_OAS_REF_ID); - expect(tryConvertToRef(schemaObject2)).toBeUndefined(); -}); - test('isNullableObjectType', () => { const any = schema.any({}); expect(isNullableObjectType(any.getSchema().describe())).toBe(false); diff --git a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/lib.ts b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/lib.ts index f5ab73d69dc53..4c7f8c999cbf4 100644 --- a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/lib.ts +++ b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/lib.ts @@ -7,7 +7,7 @@ */ import joi from 'joi'; -import { isConfigSchema, Type, metaFields } from '@kbn/config-schema'; +import { isConfigSchema, Type } from '@kbn/config-schema'; import { get } from 'lodash'; import type { OpenAPIV3 } from 'openapi-types'; import type { KnownParameters } from '../../type'; @@ -16,38 +16,6 @@ import { parse } from './parse'; import { createCtx, IContext } from './post_process_mutations'; -export const getSharedComponentId = (schema: OpenAPIV3.SchemaObject) => { - if (metaFields.META_FIELD_X_OAS_REF_ID in schema) { - return schema[metaFields.META_FIELD_X_OAS_REF_ID] as string; - } -}; - -export const removeSharedComponentId = ( - schema: OpenAPIV3.SchemaObject & { [metaFields.META_FIELD_X_OAS_REF_ID]?: string } -) => { - const { [metaFields.META_FIELD_X_OAS_REF_ID]: id, ...rest } = schema; - return rest; -}; - -export const sharedComponentIdToRef = (id: string): OpenAPIV3.ReferenceObject => { - return { - $ref: `#/components/schemas/${id}`, - }; -}; - -type IdSchemaTuple = [id: string, schema: OpenAPIV3.SchemaObject]; - -export const tryConvertToRef = (schema: OpenAPIV3.SchemaObject) => { - const sharedId = getSharedComponentId(schema); - if (sharedId) { - const idSchema: IdSchemaTuple = [sharedId, removeSharedComponentId(schema)]; - return { - idSchema, - ref: sharedComponentIdToRef(sharedId), - }; - } -}; - const isObjectType = (schema: joi.Schema | joi.Description): boolean => { return schema.type === 'object'; }; @@ -100,8 +68,8 @@ export const unwrapKbnConfigSchema = (schema: unknown): joi.Schema => { export const convert = (kbnConfigSchema: unknown) => { const schema = unwrapKbnConfigSchema(kbnConfigSchema); - const { result, shared } = parse({ schema, ctx: createCtx({ refs: true }) }); - return { schema: result, shared: Object.fromEntries(shared.entries()) }; + const { result, shared } = parse({ schema, ctx: createCtx() }); + return { schema: result, shared }; }; const convertObjectMembersToParameterObjects = ( @@ -152,11 +120,11 @@ const convertObjectMembersToParameterObjects = ( export const convertQuery = (kbnConfigSchema: unknown) => { const schema = unwrapKbnConfigSchema(kbnConfigSchema); - const ctx = createCtx({ refs: false }); // For now context is not shared between body, params and queries + const ctx = createCtx(); const result = convertObjectMembersToParameterObjects(ctx, schema, {}, false); return { query: result, - shared: Object.fromEntries(ctx.sharedSchemas.entries()), + shared: ctx.getSharedSchemas(), }; }; @@ -172,7 +140,7 @@ export const convertPathParameters = ( const result = convertObjectMembersToParameterObjects(ctx, schema, knownParameters, true); return { params: result, - shared: Object.fromEntries(ctx.sharedSchemas.entries()), + shared: ctx.getSharedSchemas(), }; }; diff --git a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/parse.test.ts b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/parse.test.ts new file mode 100644 index 0000000000000..7e9e8419d2869 --- /dev/null +++ b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/parse.test.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 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 { isJoiToJsonSpecialSchemas, joi2JsonInternal } from './parse'; + +describe('isJoiToJsonSpecialSchemas', () => { + test.each([ + [joi2JsonInternal(schema.object({ foo: schema.string() }).getSchema()), false], + [ + joi2JsonInternal( + schema.object({ foo: schema.string() }, { meta: { id: 'yes' } }).getSchema() + ), + true, + ], + [{}, false], + ])('correctly detects special schemas %#', (input, output) => { + expect(isJoiToJsonSpecialSchemas(input)).toBe(output); + }); +}); diff --git a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/parse.ts b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/parse.ts index f25cc1a4c354a..dc2349f511a05 100644 --- a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/parse.ts +++ b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/parse.ts @@ -9,6 +9,7 @@ import Joi from 'joi'; import joiToJsonParse from 'joi-to-json'; import type { OpenAPIV3 } from 'openapi-types'; +import { omit } from 'lodash'; import { createCtx, postProcessMutations } from './post_process_mutations'; import type { IContext } from './post_process_mutations'; @@ -17,13 +18,34 @@ interface ParseArgs { ctx?: IContext; } +export interface JoiToJsonReferenceObject extends OpenAPIV3.BaseSchemaObject { + schemas: { [id: string]: OpenAPIV3.SchemaObject }; +} + +type ParseResult = OpenAPIV3.SchemaObject | JoiToJsonReferenceObject; + +export const isJoiToJsonSpecialSchemas = ( + parseResult: ParseResult +): parseResult is JoiToJsonReferenceObject => { + return 'schemas' in parseResult; +}; + export const joi2JsonInternal = (schema: Joi.Schema) => { return joiToJsonParse(schema, 'open-api'); }; export const parse = ({ schema, ctx = createCtx() }: ParseArgs) => { - const parsed: OpenAPIV3.SchemaObject = joi2JsonInternal(schema); - postProcessMutations({ schema: parsed, ctx }); - const result = ctx.processRef(parsed); - return { shared: ctx.sharedSchemas, result }; + const parsed: ParseResult = joi2JsonInternal(schema); + let result: OpenAPIV3.SchemaObject; + if (isJoiToJsonSpecialSchemas(parsed)) { + Object.entries(parsed.schemas).forEach(([id, s]) => { + postProcessMutations({ schema: s, ctx }); + ctx.addSharedSchema(id, s); + }); + result = omit(parsed, 'schemas'); + } else { + result = parsed; + } + postProcessMutations({ schema: result, ctx }); + return { shared: ctx.getSharedSchemas(), result }; }; diff --git a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/context.test.ts b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/context.test.ts index 16f499f48b371..3e2a8e62516c9 100644 --- a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/context.test.ts +++ b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/context.test.ts @@ -6,41 +6,22 @@ * Side Public License, v 1. */ -import { schema, metaFields } from '@kbn/config-schema'; +import { schema } from '@kbn/config-schema'; import { joi2JsonInternal } from '../parse'; import { createCtx } from './context'; -it('does not convert and record refs by default', () => { +it('records schemas as expected', () => { const ctx = createCtx(); - const obj = schema.object({}, { meta: { id: 'foo' } }); - const parsed = joi2JsonInternal(obj.getSchema()); - const result = ctx.processRef(parsed); - expect(result).toMatchObject({ type: 'object', properties: {} }); - expect(ctx.sharedSchemas.get('foo')).toBeUndefined(); - expect(metaFields.META_FIELD_X_OAS_REF_ID in result).toBe(false); -}); - -it('can convert and record refs', () => { - const ctx = createCtx({ refs: true }); - const obj = schema.object({}, { meta: { id: 'foo' } }); - const parsed = joi2JsonInternal(obj.getSchema()); - const result = ctx.processRef(parsed); - expect(result).toEqual({ $ref: '#/components/schemas/foo' }); - expect(ctx.sharedSchemas.get('foo')).toMatchObject({ type: 'object', properties: {} }); - expect(metaFields.META_FIELD_X_OAS_REF_ID in ctx.sharedSchemas.get('foo')!).toBe(false); -}); - -it('can use provided shared schemas Map', () => { - const myMap = new Map(); - const ctx = createCtx({ refs: true, sharedSchemas: myMap }); - const obj = schema.object({}, { meta: { id: 'foo' } }); - const parsed = joi2JsonInternal(obj.getSchema()); - ctx.processRef(parsed); + const objA = schema.object({}); + const objB = schema.object({}); + const a = joi2JsonInternal(objA.getSchema()); + const b = joi2JsonInternal(objB.getSchema()); - const obj2 = schema.object({}, { meta: { id: 'bar' } }); - const parsed2 = joi2JsonInternal(obj2.getSchema()); - ctx.processRef(parsed2); + ctx.addSharedSchema('a', a); + ctx.addSharedSchema('b', b); - expect(myMap.get('foo')).toMatchObject({ type: 'object', properties: {} }); - expect(myMap.get('bar')).toMatchObject({ type: 'object', properties: {} }); + expect(ctx.getSharedSchemas()).toMatchObject({ + a: { properties: {} }, + b: { properties: {} }, + }); }); diff --git a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/context.ts b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/context.ts index 0ae440edc622e..2019d7d622481 100644 --- a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/context.ts +++ b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/context.ts @@ -7,42 +7,27 @@ */ import type { OpenAPIV3 } from 'openapi-types'; -import { processRef as processRefMutation } from './mutations/ref'; -import { removeSharedComponentId } from '../lib'; export interface IContext { - sharedSchemas: Map; - /** - * Attempt to convert a schema object to ref, my perform side-effect - * - * Will return the schema sans the ref meta ID if refs are disabled - * - * @note see also {@link Options['refs']} - */ - processRef: ( - schema: OpenAPIV3.SchemaObject - ) => OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject; + addSharedSchema: (id: string, schema: OpenAPIV3.SchemaObject) => void; + getSharedSchemas: () => { [id: string]: OpenAPIV3.SchemaObject }; } interface Options { sharedSchemas?: Map; - refs?: boolean; } class Context implements IContext { - readonly sharedSchemas: Map; - readonly refs: boolean; + private readonly sharedSchemas: Map; constructor(opts: Options) { this.sharedSchemas = opts.sharedSchemas ?? new Map(); - this.refs = !!opts.refs; } - public processRef( - schema: OpenAPIV3.SchemaObject - ): OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject { - if (this.refs) { - return processRefMutation(this, schema) ?? schema; - } - return removeSharedComponentId(schema); + public addSharedSchema(id: string, schema: OpenAPIV3.SchemaObject): void { + this.sharedSchemas.set(id, schema); + } + + public getSharedSchemas() { + return Object.fromEntries(this.sharedSchemas.entries()); } } diff --git a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/index.ts b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/index.ts index b58fbdf80de63..7d693f085ef17 100644 --- a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/index.ts +++ b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/index.ts @@ -10,9 +10,12 @@ import type { OpenAPIV3 } from 'openapi-types'; import * as mutations from './mutations'; import type { IContext } from './context'; import { isAnyType } from './mutations/utils'; +import { isReferenceObject } from '../../common'; + +type Schema = OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject; interface PostProcessMutationsArgs { - schema: OpenAPIV3.SchemaObject; + schema: Schema; ctx: IContext; } @@ -23,7 +26,9 @@ export const postProcessMutations = ({ ctx, schema }: PostProcessMutationsArgs) const arrayContainers: Array = ['allOf', 'oneOf', 'anyOf']; -const walkSchema = (ctx: IContext, schema: OpenAPIV3.SchemaObject): void => { +const walkSchema = (ctx: IContext, schema: Schema): void => { + if (isReferenceObject(schema)) return; + if (isAnyType(schema)) { mutations.processAnyType(schema); return; @@ -41,7 +46,7 @@ const walkSchema = (ctx: IContext, schema: OpenAPIV3.SchemaObject): void => { walkSchema(ctx, value as OpenAPIV3.SchemaObject); }); } - mutations.processObject(ctx, schema); + mutations.processObject(schema); } else if (type === 'string') { mutations.processString(schema); } else if (type === 'record') { @@ -57,7 +62,6 @@ const walkSchema = (ctx: IContext, schema: OpenAPIV3.SchemaObject): void => { if (schema[arrayContainer]) { schema[arrayContainer].forEach((s: OpenAPIV3.SchemaObject, idx: number) => { walkSchema(ctx, s); - schema[arrayContainer][idx] = ctx.processRef(s); }); break; } diff --git a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/index.test.ts b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/index.test.ts index cccd06855e8c4..392bca884e38e 100644 --- a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/index.test.ts +++ b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/index.test.ts @@ -15,18 +15,23 @@ test.each([ [ 'processMap', processMap, - schema.mapOf(schema.string(), schema.object({ a: schema.string() }, { meta: { id: 'myRef' } })), + schema.mapOf( + schema.string(), + schema.object({ a: schema.string() }, { meta: { id: 'myRef1' } }) + ), + 'myRef1', ], [ 'processRecord', processRecord, schema.recordOf( schema.string(), - schema.object({ a: schema.string() }, { meta: { id: 'myRef' } }) + schema.object({ a: schema.string() }, { meta: { id: 'myRef2' } }) ), + 'myRef2', ], -])('%p parses any additional properties specified', (_, processFn, obj) => { - const ctx = createCtx({ refs: true }); +])('%p parses any additional properties specified', (_, processFn, obj, refId) => { + const ctx = createCtx(); const parsed = joi2JsonInternal(obj.getSchema()); processFn(ctx, parsed); @@ -34,17 +39,19 @@ test.each([ expect(parsed).toEqual({ type: 'object', additionalProperties: { - $ref: '#/components/schemas/myRef', + $ref: `#/components/schemas/${refId}`, }, }); - expect(ctx.sharedSchemas.get('myRef')).toEqual({ - type: 'object', - additionalProperties: false, - properties: { - a: { - type: 'string', + expect(ctx.getSharedSchemas()).toEqual({ + [refId]: { + type: 'object', + additionalProperties: false, + properties: { + a: { + type: 'string', + }, }, + required: ['a'], }, - required: ['a'], }); }); diff --git a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/index.ts b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/index.ts index 02dd08b928a54..0dd6cb5dc2f84 100644 --- a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/index.ts +++ b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/index.ts @@ -48,21 +48,11 @@ const processAdditionalProperties = (ctx: IContext, schema: OpenAPIV3.SchemaObje export const processRecord = (ctx: IContext, schema: OpenAPIV3.SchemaObject): void => { schema.type = 'object'; processAdditionalProperties(ctx, schema); - if (schema.additionalProperties) { - schema.additionalProperties = ctx.processRef( - schema.additionalProperties as OpenAPIV3.SchemaObject - ); - } }; export const processMap = (ctx: IContext, schema: OpenAPIV3.SchemaObject): void => { schema.type = 'object'; processAdditionalProperties(ctx, schema); - if (schema.additionalProperties) { - schema.additionalProperties = ctx.processRef( - schema.additionalProperties as OpenAPIV3.SchemaObject - ); - } }; export const processAllTypes = (schema: OpenAPIV3.SchemaObject): void => { diff --git a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/object.test.ts b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/object.test.ts index ea54a04197277..fd7b127ef8726 100644 --- a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/object.test.ts +++ b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/object.test.ts @@ -8,7 +8,6 @@ import { schema } from '@kbn/config-schema'; import { joi2JsonInternal } from '../../parse'; -import { createCtx } from '../context'; import { processObject } from './object'; test.each([ @@ -41,36 +40,6 @@ test.each([ ], ])('processObject %#', (input, result) => { const parsed = joi2JsonInternal(input.getSchema()); - processObject(createCtx(), parsed); + processObject(parsed); expect(parsed).toEqual(result); }); - -test('refs', () => { - const fooSchema = schema.object({ n: schema.number() }, { meta: { id: 'foo' } }); - const barSchema = schema.object({ foo: fooSchema, s: schema.string() }); - const parsed = joi2JsonInternal(barSchema.getSchema()); - const ctx = createCtx({ refs: true }); - - // Simulate us walking the schema - processObject(ctx, parsed.properties.foo); - - processObject(ctx, parsed); - expect(parsed).toEqual({ - type: 'object', - additionalProperties: false, - properties: { - foo: { - $ref: '#/components/schemas/foo', - }, - s: { type: 'string' }, - }, - required: ['foo', 's'], - }); - expect(ctx.sharedSchemas.size).toBe(1); - expect(ctx.sharedSchemas.get('foo')).toEqual({ - type: 'object', - additionalProperties: false, - properties: { n: { type: 'number' } }, - required: ['n'], - }); -}); diff --git a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/object.ts b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/object.ts index 70b9b2574615b..ec5888f986bd6 100644 --- a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/object.ts +++ b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/object.ts @@ -9,7 +9,6 @@ import type { OpenAPIV3 } from 'openapi-types'; import { metaFields } from '@kbn/config-schema'; import { deleteField, stripBadDefault } from './utils'; -import { IContext } from '../context'; const { META_FIELD_X_OAS_OPTIONAL } = metaFields; @@ -51,17 +50,8 @@ const removeNeverType = (schema: OpenAPIV3.SchemaObject): void => { } }; -const processObjectRefs = (ctx: IContext, schema: OpenAPIV3.SchemaObject): void => { - if (schema.properties) { - Object.keys(schema.properties).forEach((key) => { - schema.properties![key] = ctx.processRef(schema.properties![key] as OpenAPIV3.SchemaObject); - }); - } -}; - -export const processObject = (ctx: IContext, schema: OpenAPIV3.SchemaObject): void => { +export const processObject = (schema: OpenAPIV3.SchemaObject): void => { stripBadDefault(schema); removeNeverType(schema); populateRequiredFields(schema); - processObjectRefs(ctx, schema); }; diff --git a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/ref.test.ts b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/ref.test.ts deleted file mode 100644 index 539e3cd339db6..0000000000000 --- a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/ref.test.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 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 { createCtx } from '../context'; -import { joi2JsonInternal } from '../../parse'; -import { processRef } from './ref'; - -test('create a new ref entry', () => { - const ctx = createCtx({ refs: true }); - const obj = schema.object({ a: schema.string() }, { meta: { id: 'id' } }); - const parsed = joi2JsonInternal(obj.getSchema()); - const result = processRef(ctx, parsed); - expect(result).toEqual({ - $ref: '#/components/schemas/id', - }); - expect(ctx.sharedSchemas.get('id')).toMatchObject({ - type: 'object', - properties: { - a: { - type: 'string', - }, - }, - }); -}); diff --git a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/ref.ts b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/ref.ts deleted file mode 100644 index 4b36a0245e96d..0000000000000 --- a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/ref.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 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 { OpenAPIV3 } from 'openapi-types'; -import { tryConvertToRef } from '../../lib'; -import type { IContext } from '../context'; - -export const processRef = (ctx: IContext, schema: OpenAPIV3.SchemaObject) => { - const result = tryConvertToRef(schema); - if (result) { - const [id, s] = result.idSchema; - ctx.sharedSchemas.set(id, s); - return result.ref; - } -}; diff --git a/packages/kbn-router-to-openapispec/tsconfig.json b/packages/kbn-router-to-openapispec/tsconfig.json index 7977b83701cfd..b157378320c79 100644 --- a/packages/kbn-router-to-openapispec/tsconfig.json +++ b/packages/kbn-router-to-openapispec/tsconfig.json @@ -17,6 +17,5 @@ "@kbn/core-http-router-server-internal", "@kbn/config-schema", "@kbn/core-http-server", - "@kbn/safer-lodash-set", ] } diff --git a/packages/kbn-search-connectors/lib/update_connector_index_name.ts b/packages/kbn-search-connectors/lib/update_connector_index_name.ts index 254a83812c245..279750390aaca 100644 --- a/packages/kbn-search-connectors/lib/update_connector_index_name.ts +++ b/packages/kbn-search-connectors/lib/update_connector_index_name.ts @@ -12,7 +12,7 @@ import { ElasticsearchClient } from '@kbn/core/server'; export const updateConnectorIndexName = async ( client: ElasticsearchClient, connectorId: string, - indexName: string + indexName: string | null ): Promise => { return await client.transport.request({ method: 'PUT', diff --git a/packages/kbn-server-http-tools/index.ts b/packages/kbn-server-http-tools/index.ts index a572cc6ab0832..7efa00c677015 100644 --- a/packages/kbn-server-http-tools/index.ts +++ b/packages/kbn-server-http-tools/index.ts @@ -9,8 +9,9 @@ export type { IHttpConfig, ISslConfig, ICorsConfig } from './src/types'; export { createServer } from './src/create_server'; export { defaultValidationErrorHandler } from './src/default_validation_error_handler'; -export { getListenerOptions } from './src/get_listener_options'; -export { getServerOptions, getServerTLSOptions } from './src/get_server_options'; +export { getServerListener } from './src/get_listener'; +export { getServerOptions } from './src/get_server_options'; +export { getServerTLSOptions } from './src/get_tls_options'; export { getRequestId } from './src/get_request_id'; export { setTlsConfig } from './src/set_tls_config'; export { sslSchema, SslConfig } from './src/ssl'; diff --git a/packages/kbn-server-http-tools/src/create_server.ts b/packages/kbn-server-http-tools/src/create_server.ts index 4752e342d5d3e..b57750ffaf538 100644 --- a/packages/kbn-server-http-tools/src/create_server.ts +++ b/packages/kbn-server-http-tools/src/create_server.ts @@ -7,23 +7,7 @@ */ import { Server, ServerOptions } from '@hapi/hapi'; -import { ListenerOptions } from './get_listener_options'; -export function createServer(serverOptions: ServerOptions, listenerOptions: ListenerOptions) { - const server = new Server(serverOptions); - - server.listener.keepAliveTimeout = listenerOptions.keepaliveTimeout; - server.listener.setTimeout(listenerOptions.socketTimeout); - server.listener.on('timeout', (socket) => { - socket.destroy(); - }); - server.listener.on('clientError', (err, socket) => { - if (socket.writable) { - socket.end(Buffer.from('HTTP/1.1 400 Bad Request\r\n\r\n', 'ascii')); - } else { - socket.destroy(err); - } - }); - - return server; +export function createServer(serverOptions: ServerOptions) { + return new Server(serverOptions); } diff --git a/packages/kbn-server-http-tools/src/get_listener.test.mocks.ts b/packages/kbn-server-http-tools/src/get_listener.test.mocks.ts new file mode 100644 index 0000000000000..1fab2d9191367 --- /dev/null +++ b/packages/kbn-server-http-tools/src/get_listener.test.mocks.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export const getServerTLSOptionsMock = jest.fn(); + +jest.doMock('./get_tls_options', () => { + const actual = jest.requireActual('./get_tls_options'); + return { + ...actual, + getServerTLSOptions: getServerTLSOptionsMock, + }; +}); + +export const createHttpServerMock = jest.fn(() => { + return { + on: jest.fn(), + setTimeout: jest.fn(), + }; +}); + +jest.doMock('http', () => { + const actual = jest.requireActual('http'); + return { + ...actual, + createServer: createHttpServerMock, + }; +}); + +export const createHttpsServerMock = jest.fn(() => { + return { + on: jest.fn(), + setTimeout: jest.fn(), + }; +}); + +jest.doMock('https', () => { + const actual = jest.requireActual('https'); + return { + ...actual, + createServer: createHttpsServerMock, + }; +}); diff --git a/packages/kbn-server-http-tools/src/get_listener.test.ts b/packages/kbn-server-http-tools/src/get_listener.test.ts new file mode 100644 index 0000000000000..21e0a93763490 --- /dev/null +++ b/packages/kbn-server-http-tools/src/get_listener.test.ts @@ -0,0 +1,139 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { + getServerTLSOptionsMock, + createHttpServerMock, + createHttpsServerMock, +} from './get_listener.test.mocks'; +import moment from 'moment'; +import { ByteSizeValue } from '@kbn/config-schema'; +import type { IHttpConfig } from './types'; +import { getServerListener } from './get_listener'; + +const createConfig = (parts: Partial): IHttpConfig => ({ + host: 'localhost', + port: 5601, + socketTimeout: 120000, + keepaliveTimeout: 120000, + payloadTimeout: 20000, + shutdownTimeout: moment.duration(30, 'seconds'), + maxPayload: ByteSizeValue.parse('1048576b'), + ...parts, + cors: { + enabled: false, + allowCredentials: false, + allowOrigin: ['*'], + ...parts.cors, + }, + ssl: { + enabled: false, + ...parts.ssl, + }, + restrictInternalApis: false, +}); + +describe('getServerListener', () => { + beforeEach(() => { + getServerTLSOptionsMock.mockReset(); + createHttpServerMock.mockClear(); + createHttpsServerMock.mockClear(); + }); + + describe('when TLS is enabled', () => { + it('calls getServerTLSOptions with the correct parameters', () => { + const config = createConfig({ ssl: { enabled: true } }); + + getServerListener(config); + + expect(getServerTLSOptionsMock).toHaveBeenCalledTimes(1); + expect(getServerTLSOptionsMock).toHaveBeenCalledWith(config.ssl); + }); + + it('calls https.createServer with the correct parameters', () => { + const config = createConfig({ ssl: { enabled: true } }); + + getServerTLSOptionsMock.mockReturnValue({ stub: true }); + + getServerListener(config); + + expect(createHttpsServerMock).toHaveBeenCalledTimes(1); + expect(createHttpsServerMock).toHaveBeenCalledWith({ + stub: true, + keepAliveTimeout: config.keepaliveTimeout, + }); + }); + + it('properly configures the listener', () => { + const config = createConfig({ ssl: { enabled: true } }); + const server = getServerListener(config); + + expect(server.setTimeout).toHaveBeenCalledTimes(1); + expect(server.setTimeout).toHaveBeenCalledWith(config.socketTimeout); + + expect(server.on).toHaveBeenCalledTimes(2); + expect(server.on).toHaveBeenCalledWith('clientError', expect.any(Function)); + expect(server.on).toHaveBeenCalledWith('timeout', expect.any(Function)); + }); + + it('returns the https server', () => { + const config = createConfig({ ssl: { enabled: true } }); + + const server = getServerListener(config); + + const expectedServer = createHttpsServerMock.mock.results[0].value; + + expect(server).toBe(expectedServer); + }); + }); + + describe('when TLS is disabled', () => { + it('does not call getServerTLSOptions', () => { + const config = createConfig({ ssl: { enabled: false } }); + + getServerListener(config); + + expect(getServerTLSOptionsMock).not.toHaveBeenCalled(); + }); + + it('calls http.createServer with the correct parameters', () => { + const config = createConfig({ ssl: { enabled: false } }); + + getServerTLSOptionsMock.mockReturnValue({ stub: true }); + + getServerListener(config); + + expect(createHttpServerMock).toHaveBeenCalledTimes(1); + expect(createHttpServerMock).toHaveBeenCalledWith({ + keepAliveTimeout: config.keepaliveTimeout, + }); + }); + + it('properly configures the listener', () => { + const config = createConfig({ ssl: { enabled: false } }); + const server = getServerListener(config); + + expect(server.setTimeout).toHaveBeenCalledTimes(1); + expect(server.setTimeout).toHaveBeenCalledWith(config.socketTimeout); + + expect(server.on).toHaveBeenCalledTimes(2); + expect(server.on).toHaveBeenCalledWith('clientError', expect.any(Function)); + expect(server.on).toHaveBeenCalledWith('timeout', expect.any(Function)); + }); + + it('returns the http server', () => { + const config = createConfig({ ssl: { enabled: false } }); + + const server = getServerListener(config); + + const expectedServer = createHttpServerMock.mock.results[0].value; + + expect(server).toBe(expectedServer); + }); + }); +}); diff --git a/packages/kbn-server-http-tools/src/get_listener.ts b/packages/kbn-server-http-tools/src/get_listener.ts new file mode 100644 index 0000000000000..f1dbe3de753fa --- /dev/null +++ b/packages/kbn-server-http-tools/src/get_listener.ts @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 http from 'http'; +import https from 'https'; +import { getServerTLSOptions } from './get_tls_options'; +import type { IHttpConfig, ServerListener } from './types'; + +interface GetServerListenerOptions { + configureTLS?: boolean; +} + +export function getServerListener( + config: IHttpConfig, + options: GetServerListenerOptions = {} +): ServerListener { + return configureHttp1Listener(config, options); +} + +const configureHttp1Listener = ( + config: IHttpConfig, + { configureTLS = true }: GetServerListenerOptions = {} +): ServerListener => { + const useTLS = configureTLS && config.ssl.enabled; + const tlsOptions = useTLS ? getServerTLSOptions(config.ssl) : undefined; + + const listener = useTLS + ? https.createServer({ + ...tlsOptions, + keepAliveTimeout: config.keepaliveTimeout, + }) + : http.createServer({ + keepAliveTimeout: config.keepaliveTimeout, + }); + + listener.setTimeout(config.socketTimeout); + listener.on('timeout', (socket) => { + socket.destroy(); + }); + listener.on('clientError', (err, socket) => { + if (socket.writable) { + socket.end(Buffer.from('HTTP/1.1 400 Bad Request\r\n\r\n', 'ascii')); + } else { + socket.destroy(err); + } + }); + + return listener; +}; diff --git a/packages/kbn-server-http-tools/src/get_listener_options.ts b/packages/kbn-server-http-tools/src/get_server_options.test.mocks.ts similarity index 55% rename from packages/kbn-server-http-tools/src/get_listener_options.ts rename to packages/kbn-server-http-tools/src/get_server_options.test.mocks.ts index 00884312b599f..32d808f264436 100644 --- a/packages/kbn-server-http-tools/src/get_listener_options.ts +++ b/packages/kbn-server-http-tools/src/get_server_options.test.mocks.ts @@ -6,16 +6,12 @@ * Side Public License, v 1. */ -import { IHttpConfig } from './types'; +export const getServerListenerMock = jest.fn(); -export interface ListenerOptions { - keepaliveTimeout: number; - socketTimeout: number; -} - -export function getListenerOptions(config: IHttpConfig): ListenerOptions { +jest.doMock('./get_listener', () => { + const actual = jest.requireActual('./get_listener'); return { - keepaliveTimeout: config.keepaliveTimeout, - socketTimeout: config.socketTimeout, + ...actual, + getServerListener: getServerListenerMock, }; -} +}); diff --git a/packages/kbn-server-http-tools/src/get_server_options.test.ts b/packages/kbn-server-http-tools/src/get_server_options.test.ts index 2d8f78a1405ac..00c140f46f6c7 100644 --- a/packages/kbn-server-http-tools/src/get_server_options.test.ts +++ b/packages/kbn-server-http-tools/src/get_server_options.test.ts @@ -6,10 +6,11 @@ * Side Public License, v 1. */ +import { getServerListenerMock } from './get_server_options.test.mocks'; import moment from 'moment'; import { ByteSizeValue } from '@kbn/config-schema'; +import type { IHttpConfig } from './types'; import { getServerOptions } from './get_server_options'; -import { IHttpConfig } from './types'; jest.mock('fs', () => { const original = jest.requireActual('fs'); @@ -43,69 +44,42 @@ const createConfig = (parts: Partial): IHttpConfig => ({ }); describe('getServerOptions', () => { - beforeEach(() => - jest.requireMock('fs').readFileSync.mockImplementation((path: string) => `content-${path}`) - ); + beforeEach(() => { + jest.requireMock('fs').readFileSync.mockImplementation((path: string) => `content-${path}`); + getServerListenerMock.mockReset(); + }); afterEach(() => { jest.clearAllMocks(); }); - it('properly configures TLS with default options', () => { - const httpConfig = createConfig({ - ssl: { - enabled: true, - key: 'some-key-path', - certificate: 'some-certificate-path', - }, - }); + it('calls `getServerListener` to retrieve the listener that will be provided in the config', () => { + const listener = Symbol('listener'); + getServerListenerMock.mockReturnValue(listener); - expect(getServerOptions(httpConfig).tls).toMatchInlineSnapshot(` - Object { - "ca": undefined, - "cert": "some-certificate-path", - "ciphers": undefined, - "honorCipherOrder": true, - "key": "some-key-path", - "passphrase": undefined, - "rejectUnauthorized": undefined, - "requestCert": undefined, - "secureOptions": undefined, - } - `); - }); + const httpConfig = createConfig({}); + const serverOptions = getServerOptions(httpConfig, { configureTLS: true }); - it('properly configures TLS with client authentication', () => { - const httpConfig = createConfig({ - ssl: { - enabled: true, - key: 'some-key-path', - certificate: 'some-certificate-path', - certificateAuthorities: ['ca-1', 'ca-2'], - cipherSuites: ['suite-a', 'suite-b'], - keyPassphrase: 'passPhrase', - rejectUnauthorized: true, - requestCert: true, - getSecureOptions: () => 42, - }, - }); + expect(getServerListenerMock).toHaveBeenCalledTimes(1); + expect(getServerListenerMock).toHaveBeenCalledWith(httpConfig, { configureTLS: true }); + + expect(serverOptions.listener).toBe(listener); + }); - expect(getServerOptions(httpConfig).tls).toMatchInlineSnapshot(` - Object { - "ca": Array [ - "ca-1", - "ca-2", - ], - "cert": "some-certificate-path", - "ciphers": "suite-a:suite-b", - "honorCipherOrder": true, - "key": "some-key-path", - "passphrase": "passPhrase", - "rejectUnauthorized": true, - "requestCert": true, - "secureOptions": 42, - } - `); + it('properly configures the tls option depending on the config and the configureTLS flag', () => { + expect( + getServerOptions(createConfig({ ssl: { enabled: true } }), { configureTLS: true }).tls + ).toBe(true); + expect(getServerOptions(createConfig({ ssl: { enabled: true } }), {}).tls).toBe(true); + expect( + getServerOptions(createConfig({ ssl: { enabled: true } }), { configureTLS: false }).tls + ).toBe(false); + expect( + getServerOptions(createConfig({ ssl: { enabled: false } }), { configureTLS: true }).tls + ).toBe(false); + expect( + getServerOptions(createConfig({ ssl: { enabled: false } }), { configureTLS: false }).tls + ).toBe(false); }); it('properly configures CORS when cors enabled', () => { diff --git a/packages/kbn-server-http-tools/src/get_server_options.ts b/packages/kbn-server-http-tools/src/get_server_options.ts index 37a8f5f69cc2b..fe0a669fd62f5 100644 --- a/packages/kbn-server-http-tools/src/get_server_options.ts +++ b/packages/kbn-server-http-tools/src/get_server_options.ts @@ -6,10 +6,10 @@ * Side Public License, v 1. */ -import { RouteOptionsCors, ServerOptions } from '@hapi/hapi'; -import { ServerOptions as TLSOptions } from 'https'; +import type { RouteOptionsCors, ServerOptions } from '@hapi/hapi'; +import type { IHttpConfig } from './types'; import { defaultValidationErrorHandler } from './default_validation_error_handler'; -import { IHttpConfig, ISslConfig } from './types'; +import { getServerListener } from './get_listener'; const corsAllowedHeaders = ['Accept', 'Authorization', 'Content-Type', 'If-None-Match', 'kbn-xsrf']; @@ -27,6 +27,10 @@ export function getServerOptions(config: IHttpConfig, { configureTLS = true } = const options: ServerOptions = { host: config.host, port: config.port, + // manually configuring the listener + listener: getServerListener(config, { configureTLS }), + // must set to true when manually passing a TLS listener, false otherwise + tls: configureTLS && config.ssl.enabled, routes: { cache: { privacy: 'private', @@ -51,31 +55,5 @@ export function getServerOptions(config: IHttpConfig, { configureTLS = true } = }, }; - if (configureTLS) { - options.tls = getServerTLSOptions(config.ssl); - } - return options; } - -/** - * Converts Kibana `SslConfig` into `TLSOptions` that are accepted by the Hapi server, - * and by https.Server.setSecureContext() - */ -export function getServerTLSOptions(ssl: ISslConfig): TLSOptions | undefined { - if (!ssl.enabled) { - return undefined; - } - return { - ca: ssl.certificateAuthorities, - cert: ssl.certificate, - ciphers: ssl.cipherSuites?.join(':'), - // We use the server's cipher order rather than the client's to prevent the BEAST attack. - honorCipherOrder: true, - key: ssl.key, - passphrase: ssl.keyPassphrase, - secureOptions: ssl.getSecureOptions ? ssl.getSecureOptions() : undefined, - requestCert: ssl.requestCert, - rejectUnauthorized: ssl.rejectUnauthorized, - }; -} diff --git a/packages/kbn-server-http-tools/src/get_tls_options.test.ts b/packages/kbn-server-http-tools/src/get_tls_options.test.ts new file mode 100644 index 0000000000000..0a50209db50c9 --- /dev/null +++ b/packages/kbn-server-http-tools/src/get_tls_options.test.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 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 { ByteSizeValue } from '@kbn/config-schema'; +import type { IHttpConfig } from './types'; +import { getServerTLSOptions } from './get_tls_options'; + +jest.mock('fs', () => { + const original = jest.requireActual('fs'); + return { + // Hapi Inert patches native methods + ...original, + readFileSync: jest.fn(), + }; +}); + +const createConfig = (parts: Partial): IHttpConfig => ({ + host: 'localhost', + port: 5601, + socketTimeout: 120000, + keepaliveTimeout: 120000, + payloadTimeout: 20000, + shutdownTimeout: moment.duration(30, 'seconds'), + maxPayload: ByteSizeValue.parse('1048576b'), + ...parts, + cors: { + enabled: false, + allowCredentials: false, + allowOrigin: ['*'], + ...parts.cors, + }, + ssl: { + enabled: false, + ...parts.ssl, + }, + restrictInternalApis: false, +}); + +describe('getServerTLSOptions', () => { + beforeEach(() => + jest.requireMock('fs').readFileSync.mockImplementation((path: string) => `content-${path}`) + ); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('properly configures TLS with default options', () => { + const httpConfig = createConfig({ + ssl: { + enabled: true, + key: 'some-key-path', + certificate: 'some-certificate-path', + }, + }); + + expect(getServerTLSOptions(httpConfig.ssl)).toMatchInlineSnapshot(` + Object { + "ca": undefined, + "cert": "some-certificate-path", + "ciphers": undefined, + "honorCipherOrder": true, + "key": "some-key-path", + "passphrase": undefined, + "rejectUnauthorized": undefined, + "requestCert": undefined, + "secureOptions": undefined, + } + `); + }); + + it('properly configures TLS with client authentication', () => { + const httpConfig = createConfig({ + ssl: { + enabled: true, + key: 'some-key-path', + certificate: 'some-certificate-path', + certificateAuthorities: ['ca-1', 'ca-2'], + cipherSuites: ['suite-a', 'suite-b'], + keyPassphrase: 'passPhrase', + rejectUnauthorized: true, + requestCert: true, + getSecureOptions: () => 42, + }, + }); + + expect(getServerTLSOptions(httpConfig.ssl)).toMatchInlineSnapshot(` + Object { + "ca": Array [ + "ca-1", + "ca-2", + ], + "cert": "some-certificate-path", + "ciphers": "suite-a:suite-b", + "honorCipherOrder": true, + "key": "some-key-path", + "passphrase": "passPhrase", + "rejectUnauthorized": true, + "requestCert": true, + "secureOptions": 42, + } + `); + }); +}); diff --git a/packages/kbn-server-http-tools/src/get_tls_options.ts b/packages/kbn-server-http-tools/src/get_tls_options.ts new file mode 100644 index 0000000000000..eb55327cef326 --- /dev/null +++ b/packages/kbn-server-http-tools/src/get_tls_options.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { ServerOptions as TLSOptions } from 'https'; +import { ISslConfig } from './types'; + +/** + * Converts Kibana `SslConfig` into `TLSOptions` that are accepted by the Hapi server, + * and by https.Server.setSecureContext() + */ +export function getServerTLSOptions(ssl: ISslConfig): TLSOptions | undefined { + if (!ssl.enabled) { + return undefined; + } + return { + ca: ssl.certificateAuthorities, + cert: ssl.certificate, + ciphers: ssl.cipherSuites?.join(':'), + // We use the server's cipher order rather than the client's to prevent the BEAST attack. + honorCipherOrder: true, + key: ssl.key, + passphrase: ssl.keyPassphrase, + secureOptions: ssl.getSecureOptions ? ssl.getSecureOptions() : undefined, + requestCert: ssl.requestCert, + rejectUnauthorized: ssl.rejectUnauthorized, + }; +} diff --git a/packages/kbn-server-http-tools/src/set_tls_config.test.mocks.ts b/packages/kbn-server-http-tools/src/set_tls_config.test.mocks.ts index 4b93301b334e5..597ab7d176c8e 100644 --- a/packages/kbn-server-http-tools/src/set_tls_config.test.mocks.ts +++ b/packages/kbn-server-http-tools/src/set_tls_config.test.mocks.ts @@ -8,8 +8,8 @@ export const getServerTLSOptionsMock = jest.fn(); -jest.doMock('./get_server_options', () => { - const actual = jest.requireActual('./get_server_options'); +jest.doMock('./get_tls_options', () => { + const actual = jest.requireActual('./get_tls_options'); return { ...actual, getServerTLSOptions: getServerTLSOptionsMock, diff --git a/packages/kbn-server-http-tools/src/set_tls_config.ts b/packages/kbn-server-http-tools/src/set_tls_config.ts index 1f2e1d70fa126..6b0cd35f067ea 100644 --- a/packages/kbn-server-http-tools/src/set_tls_config.ts +++ b/packages/kbn-server-http-tools/src/set_tls_config.ts @@ -7,18 +7,17 @@ */ import type { Server as HapiServer } from '@hapi/hapi'; -import type { Server as HttpServer } from 'http'; import type { Server as TlsServer } from 'https'; -import type { ISslConfig } from './types'; -import { getServerTLSOptions } from './get_server_options'; +import type { ISslConfig, ServerListener } from './types'; +import { getServerTLSOptions } from './get_tls_options'; -function isServerTLS(server: HttpServer): server is TlsServer { +function isTLSListener(server: ServerListener): server is TlsServer { return 'setSecureContext' in server; } export const setTlsConfig = (hapiServer: HapiServer, sslConfig: ISslConfig) => { const server = hapiServer.listener; - if (!isServerTLS(server)) { + if (!isTLSListener(server)) { throw new Error('tried to set TLS config on a non-TLS http server'); } const tlsOptions = getServerTLSOptions(sslConfig); diff --git a/packages/kbn-server-http-tools/src/types.ts b/packages/kbn-server-http-tools/src/types.ts index 693cb6feb46fe..88533162b2a32 100644 --- a/packages/kbn-server-http-tools/src/types.ts +++ b/packages/kbn-server-http-tools/src/types.ts @@ -6,9 +6,19 @@ * Side Public License, v 1. */ +import type { Server as HttpServer } from 'http'; +import type { Server as HttpsServer } from 'https'; import { ByteSizeValue } from '@kbn/config-schema'; import type { Duration } from 'moment'; +/** + * Composite type of all possible kind of Listener types. + * + * Unfortunately, there's no real common interface between all those concrete classes, + * as `net.Server` and `tls.Server` don't list all the APIs we're using (such as event binding) + */ +export type ServerListener = HttpServer | HttpsServer; + export interface IHttpConfig { host: string; port: number; diff --git a/packages/kbn-test/src/auth/helper.ts b/packages/kbn-test/src/auth/helper.ts index d13e3ef69f37b..fc32eab773c8e 100644 --- a/packages/kbn-test/src/auth/helper.ts +++ b/packages/kbn-test/src/auth/helper.ts @@ -20,3 +20,33 @@ export const readCloudUsersFromFile = (filePath: string): Array<[Role, User]> => return Object.entries(JSON.parse(data)) as Array<[Role, User]>; }; + +export const isValidUrl = (value: string) => { + try { + const url = new URL(value); + return url.protocol === 'http:' || url.protocol === 'https:'; + } catch (err) { + return false; + } +}; + +export const isValidHostname = (value: string) => { + if (value.length === 0) { + return false; + } + + const validChars = /^[a-zA-Z0-9-.]{1,253}\.?$/g; + if (!validChars.test(value)) { + return false; + } + + if (value.endsWith('.')) { + value = value.slice(0, value.length - 1); + } + + if (value.length > 253) { + return false; + } + + return true; +}; diff --git a/packages/kbn-test/src/auth/saml_auth.test.ts b/packages/kbn-test/src/auth/saml_auth.test.ts new file mode 100644 index 0000000000000..e64f18023a676 --- /dev/null +++ b/packages/kbn-test/src/auth/saml_auth.test.ts @@ -0,0 +1,197 @@ +/* + * Copyright 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 { ToolingLog } from '@kbn/tooling-log'; +import axios, { AxiosRequestConfig } from 'axios'; + +jest.mock('axios'); +import { + createCloudSession, + createSAMLRequest, + createSAMLResponse, + finishSAMLHandshake, +} from './saml_auth'; + +const axiosRequestMock = jest.spyOn(axios, 'request'); +const axiosGetMock = jest.spyOn(axios, 'get'); + +const log = new ToolingLog(); + +const mockRequestOnce = (mockedPath: string, response: any) => { + axiosRequestMock.mockImplementationOnce((config: AxiosRequestConfig) => { + if (config.url?.endsWith(mockedPath)) { + return Promise.resolve(response); + } + return Promise.reject(new Error(`Unexpected URL: ${config.url}`)); + }); +}; + +const mockGetOnce = (mockedUrl: string, response: any) => { + axiosGetMock.mockImplementationOnce((url: string) => { + if (url === mockedUrl) { + return Promise.resolve(response); + } + return Promise.reject(new Error(`Unexpected URL`)); + }); +}; + +describe('saml_auth', () => { + describe('createCloudSession', () => { + test('returns token value', async () => { + mockRequestOnce('/api/v1/saas/auth/_login', { data: { token: 'mocked_token' } }); + + const sessionToken = await createCloudSession({ + hostname: 'cloud', + email: 'viewer@elastic.co', + password: 'changeme', + log, + }); + expect(sessionToken).toBe('mocked_token'); + }); + + test('throws error when response has no token', async () => { + mockRequestOnce('/api/v1/saas/auth/_login', { data: { message: 'no token' } }); + + await expect( + createCloudSession({ + hostname: 'cloud', + email: 'viewer@elastic.co', + password: 'changeme', + log, + }) + ).rejects.toThrow('Unable to create Cloud session, token is missing.'); + }); + }); + + describe('createSAMLRequest', () => { + test('returns { location, sid }', async () => { + mockRequestOnce('/internal/security/login', { + data: { + location: 'https://cloud.test/saml?SAMLRequest=fVLLbtswEPwVgXe9K6%2F', + }, + headers: { + 'set-cookie': [`sid=Fe26.2**1234567890; Secure; HttpOnly; Path=/`], + }, + }); + + const response = await createSAMLRequest('https://kbn.test.co', '8.12.0', log); + expect(response).toStrictEqual({ + location: 'https://cloud.test/saml?SAMLRequest=fVLLbtswEPwVgXe9K6%2F', + sid: 'Fe26.2**1234567890', + }); + }); + + test(`throws error when response has no 'set-cookie' header`, async () => { + mockRequestOnce('/internal/security/login', { + data: { + location: 'https://cloud.test/saml?SAMLRequest=fVLLbtswEPwVgXe9K6%2F', + }, + headers: {}, + }); + + expect(createSAMLRequest('https://kbn.test.co', '8.12.0', log)).rejects.toThrow( + `Failed to parse 'set-cookie' header` + ); + }); + + test('throws error when location is not a valid url', async () => { + mockRequestOnce('/internal/security/login', { + data: { + location: 'http/.test', + }, + headers: { + 'set-cookie': [`sid=Fe26.2**1234567890; Secure; HttpOnly; Path=/`], + }, + }); + + expect(createSAMLRequest('https://kbn.test.co', '8.12.0', log)).rejects.toThrow( + `Location from Kibana SAML request is not a valid url: http/.test` + ); + }); + + test('throws error when response has no location', async () => { + const data = { error: 'mocked error' }; + mockRequestOnce('/internal/security/login', { + data, + headers: { + 'set-cookie': [`sid=Fe26.2**1234567890; Secure; HttpOnly; Path=/`], + }, + }); + + expect(createSAMLRequest('https://kbn.test.co', '8.12.0', log)).rejects.toThrow( + `Failed to get location from SAML response data: ${JSON.stringify(data)}` + ); + }); + }); + + describe('createSAMLResponse', () => { + const location = 'https://cloud.test/saml?SAMLRequest=fVLLbtswEPwVgXe9K6%2F'; + const createSAMLResponseParams = { + location, + ecSession: 'mocked_token', + email: 'viewer@elastic.co', + kbnHost: 'https://kbn.test.co', + log, + }; + + test('returns valid saml response', async () => { + mockGetOnce(location, { + data: `Test`, + }); + + const actualResponse = await createSAMLResponse(createSAMLResponseParams); + expect(actualResponse).toBe('PD94bWluc2U+'); + }); + + test('throws error when failed to parse SAML response value', async () => { + mockGetOnce(location, { + data: `Test`, + }); + + await expect(createSAMLResponse(createSAMLResponseParams)).rejects + .toThrowError(`Failed to parse SAML response value.\nMost likely the 'viewer@elastic.co' user has no access to the cloud deployment. +Login to ${ + new URL(location).hostname + } with the user from '.ftr/role_users.json' file and try to load +https://kbn.test.co in the same window.`); + }); + }); + + describe('finishSAMLHandshake', () => { + const cookieStr = 'mocked_cookie'; + test('returns valid cookie', async () => { + mockRequestOnce('/api/security/saml/callback', { + headers: { + 'set-cookie': [`sid=${cookieStr}; Secure; HttpOnly; Path=/`], + }, + }); + + const response = await finishSAMLHandshake({ + kbnHost: 'https://kbn.test.co', + samlResponse: 'PD94bWluc2U+', + sid: 'Fe26.2**1234567890', + log, + }); + expect(response.key).toEqual('sid'); + expect(response.value).toEqual(cookieStr); + }); + + test(`throws error when response has no 'set-cookie' header`, async () => { + mockRequestOnce('/api/security/saml/callback', { headers: {} }); + + await expect( + finishSAMLHandshake({ + kbnHost: 'https://kbn.test.co', + samlResponse: 'PD94bWluc2U+', + sid: 'Fe26.2**1234567890', + log, + }) + ).rejects.toThrow(`Failed to parse 'set-cookie' header`); + }); + }); +}); diff --git a/packages/kbn-test/src/auth/saml_auth.ts b/packages/kbn-test/src/auth/saml_auth.ts index bd570188922e6..a88d11c6a5bc9 100644 --- a/packages/kbn-test/src/auth/saml_auth.ts +++ b/packages/kbn-test/src/auth/saml_auth.ts @@ -12,10 +12,12 @@ import axios, { AxiosResponse } from 'axios'; import * as cheerio from 'cheerio'; import { Cookie, parse as parseCookie } from 'tough-cookie'; import Url from 'url'; +import { isValidHostname, isValidUrl } from './helper'; import { CloudSamlSessionParams, CreateSamlSessionParams, LocalSamlSessionParams, + SAMLResponseValueParams, UserProfile, } from './types'; @@ -50,13 +52,23 @@ const cleanException = (url: string, ex: any) => { } }; -const getSessionCookie = (cookieString: string) => { - return parseCookie(cookieString); +const getCookieFromResponseHeaders = (response: AxiosResponse, errorMessage: string) => { + const setCookieHeader = response?.headers['set-cookie']; + if (!setCookieHeader) { + throw new Error(`Failed to parse 'set-cookie' header`); + } + + const cookie = parseCookie(setCookieHeader![0]); + if (!cookie) { + throw new Error(errorMessage); + } + + return cookie; }; const getCloudHostName = () => { const hostname = process.env.TEST_CLOUD_HOST_NAME; - if (!hostname) { + if (!hostname || !isValidHostname(hostname)) { throw new Error('SAML Authentication requires TEST_CLOUD_HOST_NAME env variable to be set'); } @@ -71,7 +83,7 @@ const getCloudUrl = (hostname: string, pathname: string) => { }); }; -const createCloudSession = async (params: CreateSamlSessionParams) => { +export const createCloudSession = async (params: CreateSamlSessionParams) => { const { hostname, email, password, log } = params; const cloudLoginUrl = getCloudUrl(hostname, '/api/v1/saas/auth/_login'); let sessionResponse: AxiosResponse | undefined; @@ -112,7 +124,7 @@ const createCloudSession = async (params: CreateSamlSessionParams) => { return token; }; -const createSAMLRequest = async (kbnUrl: string, kbnVersion: string, log: ToolingLog) => { +export const createSAMLRequest = async (kbnUrl: string, kbnVersion: string, log: ToolingLog) => { let samlResponse: AxiosResponse; const url = kbnUrl + '/internal/security/login'; try { @@ -138,10 +150,10 @@ const createSAMLRequest = async (kbnUrl: string, kbnVersion: string, log: Toolin throw ex; } - const cookie = getSessionCookie(samlResponse.headers['set-cookie']![0]); - if (!cookie) { - throw new Error(`Failed to parse cookie from SAML response headers`); - } + const cookie = getCookieFromResponseHeaders( + samlResponse, + 'Failed to parse cookie from SAML response headers' + ); const location = samlResponse?.data?.location as string; if (!location) { @@ -149,24 +161,46 @@ const createSAMLRequest = async (kbnUrl: string, kbnVersion: string, log: Toolin `Failed to get location from SAML response data: ${JSON.stringify(samlResponse.data)}` ); } + if (!isValidUrl(location)) { + throw new Error(`Location from Kibana SAML request is not a valid url: ${location}`); + } return { location, sid: cookie.value }; }; -const createSAMLResponse = async (url: string, ecSession: string) => { - const samlResponse = await axios.get(url, { - headers: { - Cookie: `ec_session=${ecSession}`, - }, - }); - const $ = cheerio.load(samlResponse.data); - const value = $('input').attr('value') ?? ''; - if (value.length === 0) { - throw new Error('Failed to parse SAML response value'); +export const createSAMLResponse = async (params: SAMLResponseValueParams) => { + const { location, ecSession, email, kbnHost, log } = params; + let samlResponse: AxiosResponse; + let value: string | undefined; + try { + samlResponse = await axios.get(location, { + headers: { + Cookie: `ec_session=${ecSession}`, + }, + maxRedirects: 0, + }); + const $ = cheerio.load(samlResponse.data); + value = $('input').attr('value'); + } catch (err) { + if (err.isAxiosError) { + log.error( + `Create SAML Response failed with status code ${err?.response?.status}: ${err?.response?.data}` + ); + } } + + if (!value) { + const hostname = new URL(location).hostname; + throw new Error( + `Failed to parse SAML response value.\nMost likely the '${email}' user has no access to the cloud deployment. +Login to ${hostname} with the user from '.ftr/role_users.json' file and try to load +${kbnHost} in the same window.` + ); + } + return value; }; -const finishSAMLHandshake = async ({ +export const finishSAMLHandshake = async ({ kbnHost, samlResponse, sid, @@ -199,12 +233,10 @@ const finishSAMLHandshake = async ({ throw ex; } - const cookie = getSessionCookie(authResponse!.headers['set-cookie']![0]); - if (!cookie) { - throw new Error(`Failed to get cookie from SAML callback response headers`); - } - - return cookie; + return getCookieFromResponseHeaders( + authResponse, + 'Failed to get cookie from SAML callback response headers' + ); }; const getSecurityProfile = async ({ @@ -238,9 +270,9 @@ const getSecurityProfile = async ({ export const createCloudSAMLSession = async (params: CloudSamlSessionParams) => { const { email, password, kbnHost, kbnVersion, log } = params; const hostname = getCloudHostName(); - const token = await createCloudSession({ hostname, email, password, log }); + const ecSession = await createCloudSession({ hostname, email, password, log }); const { location, sid } = await createSAMLRequest(kbnHost, kbnVersion, log); - const samlResponse = await createSAMLResponse(location, token); + const samlResponse = await createSAMLResponse({ location, ecSession, email, kbnHost, log }); const cookie = await finishSAMLHandshake({ kbnHost, samlResponse, sid, log }); const userProfile = await getSecurityProfile({ kbnHost, cookie, log }); return new Session(cookie, email, userProfile.full_name); diff --git a/packages/kbn-test/src/auth/sesson_manager.test.ts b/packages/kbn-test/src/auth/sesson_manager.test.ts index 4332a3630bfe9..f0679917654a0 100644 --- a/packages/kbn-test/src/auth/sesson_manager.test.ts +++ b/packages/kbn-test/src/auth/sesson_manager.test.ts @@ -24,6 +24,7 @@ const roleEditor = 'editor'; const createLocalSAMLSessionMock = jest.spyOn(samlAuth, 'createLocalSAMLSession'); const createCloudSAMLSessionMock = jest.spyOn(samlAuth, 'createCloudSAMLSession'); const readCloudUsersFromFileMock = jest.spyOn(helper, 'readCloudUsersFromFile'); +const isValidHostnameMock = jest.spyOn(helper, 'isValidHostname'); jest.mock('../kbn_client/kbn_client', () => { return { @@ -130,19 +131,6 @@ describe('SamlSessionManager', () => { }); describe('for cloud session', () => { - beforeEach(() => { - jest.resetAllMocks(); - jest - .requireMock('../kbn_client/kbn_client') - .KbnClient.mockImplementation(() => ({ version: { get } })); - get.mockImplementationOnce(() => Promise.resolve('8.12.0')); - - createCloudSAMLSessionMock.mockResolvedValue( - new Session(cloudCookieInstance, cloudEmail, cloudFullname) - ); - readCloudUsersFromFileMock.mockReturnValue(cloudUsers); - }); - const hostOptions = { protocol: 'https' as 'http' | 'https', hostname: 'cloud', @@ -165,6 +153,43 @@ describe('SamlSessionManager', () => { cloudUsers.push(['viewer', { email: 'viewer@elastic.co', password: 'p1234' }]); cloudUsers.push(['editor', { email: 'editor@elastic.co', password: 'p1234' }]); + describe('handles errors', () => { + beforeEach(() => { + jest.resetAllMocks(); + jest + .requireMock('../kbn_client/kbn_client') + .KbnClient.mockImplementation(() => ({ version: { get } })); + get.mockImplementationOnce(() => Promise.resolve('8.12.0')); + + readCloudUsersFromFileMock.mockReturnValue(cloudUsers); + }); + + test('should throw error if TEST_CLOUD_HOST_NAME is not set', async () => { + isValidHostnameMock.mockReturnValueOnce(false); + const samlSessionManager = new SamlSessionManager({ + hostOptions, + log, + isCloud, + }); + await expect(samlSessionManager.getSessionCookieForRole(roleViewer)).rejects.toThrow( + 'SAML Authentication requires TEST_CLOUD_HOST_NAME env variable to be set' + ); + }); + }); + + beforeEach(() => { + jest.resetAllMocks(); + jest + .requireMock('../kbn_client/kbn_client') + .KbnClient.mockImplementation(() => ({ version: { get } })); + get.mockImplementationOnce(() => Promise.resolve('8.12.0')); + + createCloudSAMLSessionMock.mockResolvedValue( + new Session(cloudCookieInstance, cloudEmail, cloudFullname) + ); + readCloudUsersFromFileMock.mockReturnValue(cloudUsers); + }); + test('should create an instance of SamlSessionManager', () => { const samlSessionManager = new SamlSessionManager({ hostOptions, diff --git a/packages/kbn-test/src/auth/types.ts b/packages/kbn-test/src/auth/types.ts index 17b5183ab9967..62ee5ac428934 100644 --- a/packages/kbn-test/src/auth/types.ts +++ b/packages/kbn-test/src/auth/types.ts @@ -32,6 +32,14 @@ export interface CreateSamlSessionParams { log: ToolingLog; } +export interface SAMLResponseValueParams { + location: string; + ecSession: string; + email: string; + kbnHost: string; + log: ToolingLog; +} + export interface User { readonly email: string; readonly password: string; diff --git a/packages/kbn-text-based-editor/src/helpers.ts b/packages/kbn-text-based-editor/src/helpers.ts index d8f4fac7f51a2..d2a429a6e0b1d 100644 --- a/packages/kbn-text-based-editor/src/helpers.ts +++ b/packages/kbn-text-based-editor/src/helpers.ts @@ -228,3 +228,11 @@ export const clearCacheWhenOld = (cache: MapCache, esqlQuery: string) => { } } }; + +export const getESQLSources = async (dataViews: DataViewsPublicPluginStart) => { + const [remoteIndices, localIndices] = await Promise.all([ + getRemoteIndicesList(dataViews), + getIndicesList(dataViews), + ]); + return [...localIndices, ...remoteIndices]; +}; 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 fd20d9c2b25ca..4d50abd3f9647 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 @@ -50,9 +50,8 @@ import { type MonacoMessage, getWrappedInPipesCode, parseErrors, - getIndicesList, - getRemoteIndicesList, clearCacheWhenOld, + getESQLSources, } from './helpers'; import { EditorFooter } from './editor_footer'; import { ResizableButton } from './resizable_button'; @@ -183,6 +182,23 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ const [isCompactFocused, setIsCompactFocused] = useState(isCodeEditorExpanded); const [isCodeEditorExpandedFocused, setIsCodeEditorExpandedFocused] = useState(false); const [isQueryLoading, setIsQueryLoading] = useState(true); + + const editorShouldNotValidate = useMemo(() => { + return ( + isLoading || + isDisabled || + Boolean(!isCompactFocused && codeOneLiner && codeOneLiner.includes('...')) || + Boolean(!isCodeEditorExpandedFocused && queryString === '') + ); + }, [ + codeOneLiner, + isCodeEditorExpandedFocused, + isCompactFocused, + isDisabled, + isLoading, + queryString, + ]); + const [abortController, setAbortController] = useState(new AbortController()); // contains both client side validation and server messages const [editorMessages, setEditorMessages] = useState<{ @@ -359,14 +375,24 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ return { cache: fn.cache, memoizedFieldsFromESQL: fn }; }, []); + const { cache: dataSourcesCache, memoizedSources } = useMemo(() => { + const fn = memoize( + (...args: [DataViewsPublicPluginStart]) => ({ + timestamp: Date.now(), + result: getESQLSources(...args), + }), + ({ esql }) => esql + ); + + return { cache: fn.cache, memoizedSources: fn }; + }, []); + const esqlCallbacks: ESQLCallbacks = useMemo(() => { const callbacks: ESQLCallbacks = { getSources: async () => { - const [remoteIndices, localIndices] = await Promise.all([ - getRemoteIndicesList(dataViews), - getIndicesList(dataViews), - ]); - return [...localIndices, ...remoteIndices]; + clearCacheWhenOld(dataSourcesCache, queryString); + const sources = await memoizedSources(dataViews).result; + return sources; }, getFieldsFor: async ({ query: queryToExecute }: { query?: string } | undefined = {}) => { if (queryToExecute) { @@ -402,12 +428,15 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ }; return callbacks; }, [ + queryString, + memoizedSources, + dataSourcesCache, dataViews, - expressions, - indexManagementApiService, esqlFieldsCache, memoizedFieldsFromESQL, + expressions, abortController, + indexManagementApiService, ]); const parseMessages = useCallback(async () => { @@ -451,9 +480,16 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ } }, [clientParserMessages, isLoading, isQueryLoading, parseMessages, queryString, timeZone]); + useEffect(() => { + if (code === '') { + setEditorMessages({ errors: [], warnings: [] }); + } + }, [code]); + const queryValidation = useCallback( async ({ active }: { active: boolean }) => { - if (!editorModel.current || language !== 'esql' || editorModel.current.isDisposed()) return; + if (!editorModel.current || language !== 'esql' || editorModel.current.isDisposed() || !code) + return; monaco.editor.setModelMarkers(editorModel.current, 'Unified search', []); const { warnings: parserWarnings, errors: parserErrors } = await parseMessages(); const markers = []; @@ -467,12 +503,12 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ return; } }, - [language, parseMessages] + [code, language, parseMessages] ); useDebounceWithOptions( async () => { - if (!editorModel.current) return; + if (!editorModel.current || editorShouldNotValidate) return; const subscription = { active: true }; if (code === codeWhenSubmitted && (serverErrors || serverWarning)) { const parsedErrors = parseErrors(serverErrors || [], code); @@ -642,10 +678,7 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ lightbulb: { enabled: false, }, - readOnly: - isLoading || - isDisabled || - Boolean(!isCompactFocused && codeOneLiner && codeOneLiner.includes('...')), + readOnly: editorShouldNotValidate, }; if (isCompactFocused) { diff --git a/packages/kbn-unified-field-list/src/components/field_categorize_button/categorize_trigger_utils.test.ts b/packages/kbn-unified-field-list/src/components/field_categorize_button/categorize_trigger_utils.test.ts deleted file mode 100644 index a0efbaf8de869..0000000000000 --- a/packages/kbn-unified-field-list/src/components/field_categorize_button/categorize_trigger_utils.test.ts +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 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 { DataViewField, DataView } from '@kbn/data-views-plugin/public'; -import type { Action, UiActionsStart } from '@kbn/ui-actions-plugin/public'; -import { canCategorize } from './categorize_trigger_utils'; - -const textField = { - name: 'fieldName', - type: 'string', - esTypes: ['text'], - count: 1, - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: true, - visualizable: true, -} as DataViewField; - -const numberField = { - name: 'fieldName', - type: 'number', - esTypes: ['double'], - count: 1, - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: true, - visualizable: true, -} as DataViewField; - -const mockGetActions = jest.fn>>, [string, { fieldName: string }]>( - () => Promise.resolve([]) -); - -const uiActions = { - getTriggerCompatibleActions: mockGetActions, -} as unknown as UiActionsStart; - -const action: Action = { - id: 'action', - type: 'CATEGORIZE_FIELD', - getIconType: () => undefined, - getDisplayName: () => 'Action', - isCompatible: () => Promise.resolve(true), - execute: () => Promise.resolve(), -}; - -const dataViewMock = { id: '1', toSpec: () => ({}), isTimeBased: () => true } as DataView; - -describe('categorize_trigger_utils', () => { - afterEach(() => { - mockGetActions.mockReset(); - }); - - describe('getCategorizeInformation', () => { - it('should return true for a categorizable field with an action', async () => { - mockGetActions.mockResolvedValue([action]); - const resp = await canCategorize(uiActions, textField, dataViewMock); - expect(resp).toBe(true); - }); - - it('should return false for a non-categorizable field with an action', async () => { - mockGetActions.mockResolvedValue([action]); - const resp = await canCategorize(uiActions, numberField, dataViewMock); - expect(resp).toBe(false); - }); - }); -}); diff --git a/packages/kbn-unified-field-list/src/components/field_categorize_button/categorize_trigger_utils.ts b/packages/kbn-unified-field-list/src/components/field_categorize_button/categorize_trigger_utils.ts deleted file mode 100644 index 007a88b2c7f97..0000000000000 --- a/packages/kbn-unified-field-list/src/components/field_categorize_button/categorize_trigger_utils.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 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 { UiActionsStart } from '@kbn/ui-actions-plugin/public'; -import { CATEGORIZE_FIELD_TRIGGER, type CategorizeFieldContext } from '@kbn/ml-ui-actions'; -import type { DataViewField, DataView } from '@kbn/data-views-plugin/public'; - -async function getCompatibleActions( - uiActions: UiActionsStart, - field: DataViewField, - dataView: DataView, - trigger: typeof CATEGORIZE_FIELD_TRIGGER -) { - const compatibleActions = await uiActions.getTriggerCompatibleActions(trigger, { - dataView, - field, - }); - return compatibleActions; -} - -export function triggerCategorizeActions( - uiActions: UiActionsStart, - field: DataViewField, - originatingApp: string, - dataView?: DataView -) { - if (!dataView) return; - const triggerOptions: CategorizeFieldContext = { - dataView, - field, - originatingApp, - }; - uiActions.getTrigger(CATEGORIZE_FIELD_TRIGGER).exec(triggerOptions); -} - -export async function canCategorize( - uiActions: UiActionsStart, - field: DataViewField, - dataView: DataView | undefined -): Promise { - if ( - field.name === '_id' || - !dataView?.id || - !dataView.isTimeBased() || - !field.esTypes?.includes('text') - ) { - return false; - } - - const actions = await getCompatibleActions(uiActions, field, dataView, CATEGORIZE_FIELD_TRIGGER); - - return actions.length > 0; -} diff --git a/packages/kbn-unified-field-list/src/components/field_categorize_button/field_categorize_button.test.tsx b/packages/kbn-unified-field-list/src/components/field_categorize_button/field_categorize_button.test.tsx deleted file mode 100644 index 45569b3443370..0000000000000 --- a/packages/kbn-unified-field-list/src/components/field_categorize_button/field_categorize_button.test.tsx +++ /dev/null @@ -1,94 +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 { act } from 'react-dom/test-utils'; -import { ReactWrapper } from 'enzyme'; -import { EuiButton } from '@elastic/eui'; -import { mountWithIntl } from '@kbn/test-jest-helpers'; -import { stubLogstashDataView as dataView } from '@kbn/data-views-plugin/common/data_view.stub'; -import { ActionInternal } from '@kbn/ui-actions-plugin/public'; -import { uiActionsPluginMock } from '@kbn/ui-actions-plugin/public/mocks'; -import { getFieldCategorizeButton } from './field_categorize_button'; -import { - CATEGORIZE_FIELD_TRIGGER, - ACTION_CATEGORIZE_FIELD, - type CategorizeFieldContext, -} from '@kbn/ml-ui-actions'; -import { TriggerContract } from '@kbn/ui-actions-plugin/public/triggers'; - -const ORIGINATING_APP = 'test'; -const mockExecuteAction = jest.fn(); -const uiActions = uiActionsPluginMock.createStartContract(); -const categorizeAction = new ActionInternal({ - type: ACTION_CATEGORIZE_FIELD, - id: ACTION_CATEGORIZE_FIELD, - getDisplayName: () => 'test', - isCompatible: async () => true, - execute: async (context: CategorizeFieldContext) => { - mockExecuteAction(context); - }, - getHref: async () => '/app/test', -}); - -jest - .spyOn(uiActions, 'getTriggerCompatibleActions') - .mockResolvedValue([categorizeAction as ActionInternal]); -jest.spyOn(uiActions, 'getTrigger').mockReturnValue({ - id: ACTION_CATEGORIZE_FIELD, - exec: mockExecuteAction, -} as unknown as TriggerContract); - -describe('UnifiedFieldList ', () => { - it('should render correctly', async () => { - const fieldName = 'extension'; - const field = dataView.fields.find((f) => f.name === fieldName)!; - let wrapper: ReactWrapper; - - const button = await getFieldCategorizeButton({ - field, - dataView, - originatingApp: ORIGINATING_APP, - uiActions, - }); - await act(async () => { - wrapper = await mountWithIntl(button!); - }); - - await wrapper!.update(); - - expect(uiActions.getTriggerCompatibleActions).toHaveBeenCalledWith(CATEGORIZE_FIELD_TRIGGER, { - dataView, - field, - }); - - expect(wrapper!.text()).toBe('Run pattern analysis'); - wrapper!.find(`button[data-test-subj="fieldCategorize-${fieldName}"]`).simulate('click'); - - expect(mockExecuteAction).toHaveBeenCalledWith({ - dataView, - field, - originatingApp: ORIGINATING_APP, - }); - - expect(wrapper!.find(EuiButton).exists()).toBeTruthy(); - }); - - it('should not render for non text field', async () => { - const fieldName = 'phpmemory'; - const field = dataView.fields.find((f) => f.name === fieldName)!; - - const button = await getFieldCategorizeButton({ - field, - dataView, - originatingApp: ORIGINATING_APP, - uiActions, - }); - - expect(button).toBe(null); - }); -}); diff --git a/packages/kbn-unified-field-list/src/components/field_categorize_button/field_categorize_button.tsx b/packages/kbn-unified-field-list/src/components/field_categorize_button/field_categorize_button.tsx deleted file mode 100644 index 5914c330f6661..0000000000000 --- a/packages/kbn-unified-field-list/src/components/field_categorize_button/field_categorize_button.tsx +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 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 { EuiButtonProps } from '@elastic/eui'; -import { METRIC_TYPE, UiCounterMetricType } from '@kbn/analytics'; -import type { DataView, DataViewField } from '@kbn/data-views-plugin/public'; -import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; -import { FieldCategorizeButtonInner } from './field_categorize_button_inner'; -import { triggerCategorizeActions, canCategorize } from './categorize_trigger_utils'; - -export interface FieldCategorizeButtonProps { - field: DataViewField; - dataView: DataView; - originatingApp: string; // plugin id - uiActions: UiActionsStart; - contextualFields?: string[]; // names of fields which were also selected (like columns in Discover grid) - trackUiMetric?: (metricType: UiCounterMetricType, eventName: string | string[]) => void; - buttonProps?: Partial; - closePopover?: () => void; -} - -export const FieldCategorizeButton: React.FC = React.memo( - ({ field, dataView, trackUiMetric, originatingApp, uiActions, buttonProps, closePopover }) => { - const handleVisualizeLinkClick = async ( - event: React.MouseEvent - ) => { - // regular link click. let the uiActions code handle the navigation and show popup if needed - event.preventDefault(); - const triggerVisualization = (updatedDataView: DataView) => { - trackUiMetric?.(METRIC_TYPE.CLICK, 'categorize_link_click'); - triggerCategorizeActions(uiActions, field, originatingApp, updatedDataView); - }; - triggerVisualization(dataView); - if (closePopover) { - closePopover(); - } - }; - - return ( - - ); - } -); - -export async function getFieldCategorizeButton(props: FieldCategorizeButtonProps) { - const showButton = await canCategorize(props.uiActions, props.field, props.dataView); - return showButton ? : null; -} diff --git a/packages/kbn-unified-field-list/src/components/field_categorize_button/field_categorize_button_inner.tsx b/packages/kbn-unified-field-list/src/components/field_categorize_button/field_categorize_button_inner.tsx deleted file mode 100644 index 8571822dcd8e9..0000000000000 --- a/packages/kbn-unified-field-list/src/components/field_categorize_button/field_categorize_button_inner.tsx +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 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 { EuiButton, EuiButtonProps } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; - -interface FieldVisualizeButtonInnerProps { - fieldName: string; - handleVisualizeLinkClick: (event: React.MouseEvent) => void; - buttonProps?: Partial; -} - -export const FieldCategorizeButtonInner: React.FC = ({ - fieldName, - handleVisualizeLinkClick, - buttonProps, -}) => { - return ( - <> - - - - - ); -}; diff --git a/packages/kbn-unified-field-list/src/components/field_popover/field_popover_footer.tsx b/packages/kbn-unified-field-list/src/components/field_popover/field_popover_footer.tsx index bde3120708ef6..95378ba8b327b 100644 --- a/packages/kbn-unified-field-list/src/components/field_popover/field_popover_footer.tsx +++ b/packages/kbn-unified-field-list/src/components/field_popover/field_popover_footer.tsx @@ -7,16 +7,14 @@ */ import React, { useEffect, useState } from 'react'; -import { EuiPopoverFooter, EuiSpacer } from '@elastic/eui'; +import { EuiPopoverFooter } from '@elastic/eui'; import { type FieldVisualizeButtonProps, getFieldVisualizeButton } from '../field_visualize_button'; -import { FieldCategorizeButtonProps, getFieldCategorizeButton } from '../field_categorize_button'; import { ErrorBoundary } from '../error_boundary'; -export type FieldPopoverFooterProps = FieldVisualizeButtonProps | FieldCategorizeButtonProps; +export type FieldPopoverFooterProps = FieldVisualizeButtonProps; const FieldPopoverFooterComponent: React.FC = (props) => { const [visualizeButton, setVisualizeButton] = useState(null); - const [categorizeButton, setCategorizeButton] = useState(null); useEffect(() => { getFieldVisualizeButton(props) @@ -25,21 +23,9 @@ const FieldPopoverFooterComponent: React.FC = (props) = // eslint-disable-next-line no-console console.error(error); }); - getFieldCategorizeButton(props) - .then(setCategorizeButton) - .catch((error) => { - // eslint-disable-next-line no-console - console.error(error); - }); }, [props]); - return visualizeButton || categorizeButton ? ( - - {visualizeButton} - {visualizeButton && categorizeButton ? : null} - {categorizeButton} - - ) : null; + return visualizeButton ? {visualizeButton} : null; }; export const FieldPopoverFooter: React.FC = (props) => { 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 409184c4d8e04..d9e02d423cd9e 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 @@ -309,7 +309,6 @@ function UnifiedFieldListItemComponent({ contextualFields={workspaceSelectedFieldNames} originatingApp={stateService.creationOptions.originatingApp} uiActions={services.uiActions} - closePopover={() => closePopover()} /> )} diff --git a/packages/kbn-unified-field-list/tsconfig.json b/packages/kbn-unified-field-list/tsconfig.json index 6dc268783d89a..acad1797d26ff 100644 --- a/packages/kbn-unified-field-list/tsconfig.json +++ b/packages/kbn-unified-field-list/tsconfig.json @@ -31,7 +31,6 @@ "@kbn/ebt-tools", "@kbn/shared-ux-button-toolbar", "@kbn/field-utils", - "@kbn/ml-ui-actions", "@kbn/visualization-utils", "@kbn/esql-utils", "@kbn/search-types" diff --git a/packages/presentation/presentation_containers/index.ts b/packages/presentation/presentation_containers/index.ts index f6049b284eae2..89b327801d289 100644 --- a/packages/presentation/presentation_containers/index.ts +++ b/packages/presentation/presentation_containers/index.ts @@ -8,10 +8,15 @@ export { apiCanAddNewPanel, type CanAddNewPanel } from './interfaces/can_add_new_panel'; export { - apiPublishesLastSavedState, - getLastSavedStateSubjectForChild, - type PublishesLastSavedState, -} from './interfaces/last_saved_state'; + apiHasRuntimeChildState, + apiHasSerializedChildState, + type HasRuntimeChildState, + type HasSerializedChildState, +} from './interfaces/child_state'; +export { + apiHasSaveNotification, + type HasSaveNotification, +} from './interfaces/has_save_notification'; export { apiCanDuplicatePanels, apiCanExpandPanels, @@ -25,13 +30,14 @@ export { type PanelPackage, type PresentationContainer, } from './interfaces/presentation_container'; -export { - canTrackContentfulRender, - type TrackContentfulRender, -} from './interfaces/track_contentful_render'; export { apiHasSerializableState, type HasSerializableState, + type HasSnapshottableState, type SerializedPanelState, } from './interfaces/serialized_state'; export { tracksOverlays, type TracksOverlays } from './interfaces/tracks_overlays'; +export { + canTrackContentfulRender, + type TrackContentfulRender, +} from './interfaces/track_contentful_render'; diff --git a/packages/presentation/presentation_containers/interfaces/child_state.ts b/packages/presentation/presentation_containers/interfaces/child_state.ts new file mode 100644 index 0000000000000..c197974c67add --- /dev/null +++ b/packages/presentation/presentation_containers/interfaces/child_state.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { SerializedPanelState } from './serialized_state'; + +export interface HasSerializedChildState { + getSerializedStateForChild: (childId: string) => SerializedPanelState; +} + +export interface HasRuntimeChildState { + getRuntimeStateForChild: (childId: string) => Partial | undefined; +} + +export const apiHasSerializedChildState = ( + api: unknown +): api is HasSerializedChildState => { + return Boolean(api && (api as HasSerializedChildState).getSerializedStateForChild); +}; + +export const apiHasRuntimeChildState = ( + api: unknown +): api is HasRuntimeChildState => { + return Boolean(api && (api as HasRuntimeChildState).getRuntimeStateForChild); +}; diff --git a/packages/presentation/presentation_containers/interfaces/has_save_notification.ts b/packages/presentation/presentation_containers/interfaces/has_save_notification.ts new file mode 100644 index 0000000000000..0607b83a12955 --- /dev/null +++ b/packages/presentation/presentation_containers/interfaces/has_save_notification.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { Subject } from 'rxjs'; + +export interface HasSaveNotification { + saveNotification$: Subject; // a notification that state has been saved +} + +export const apiHasSaveNotification = (api: unknown): api is HasSaveNotification => { + return Boolean(api && (api as HasSaveNotification).saveNotification$); +}; diff --git a/packages/presentation/presentation_containers/interfaces/last_saved_state.ts b/packages/presentation/presentation_containers/interfaces/last_saved_state.ts deleted file mode 100644 index b4e4664920f11..0000000000000 --- a/packages/presentation/presentation_containers/interfaces/last_saved_state.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 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 { PublishingSubject } from '@kbn/presentation-publishing'; -import { BehaviorSubject, Subject } from 'rxjs'; -import { filter, map } from 'rxjs'; -import { SerializedPanelState } from './serialized_state'; - -export interface PublishesLastSavedState { - lastSavedState: Subject; // a notification that the last saved state has changed - getLastSavedStateForChild: ( - childId: string - ) => SerializedPanelState | undefined; -} - -export const apiPublishesLastSavedState = (api: unknown): api is PublishesLastSavedState => { - return Boolean( - api && - (api as PublishesLastSavedState).lastSavedState && - (api as PublishesLastSavedState).getLastSavedStateForChild - ); -}; - -export const getLastSavedStateSubjectForChild = < - SerializedState extends object = object, - RuntimeState extends object = object ->( - parentApi: unknown, - childId: string, - deserializer: (state: SerializedPanelState) => RuntimeState -): PublishingSubject | undefined => { - if (!parentApi) return; - const fetchLastSavedState = (): RuntimeState | undefined => { - if (!apiPublishesLastSavedState(parentApi)) return; - const rawLastSavedState = parentApi.getLastSavedStateForChild(childId); - if (rawLastSavedState === undefined) return; - return deserializer(rawLastSavedState); - }; - - const lastSavedStateForChild = new BehaviorSubject( - fetchLastSavedState() - ); - if (!apiPublishesLastSavedState(parentApi)) return; - parentApi.lastSavedState - .pipe( - map(() => fetchLastSavedState()), - filter((rawLastSavedState) => rawLastSavedState !== undefined) - ) - .subscribe(lastSavedStateForChild); - return lastSavedStateForChild; -}; diff --git a/packages/presentation/presentation_containers/interfaces/serialized_state.ts b/packages/presentation/presentation_containers/interfaces/serialized_state.ts index f56dd215bbcda..9678e5a1faeca 100644 --- a/packages/presentation/presentation_containers/interfaces/serialized_state.ts +++ b/packages/presentation/presentation_containers/interfaces/serialized_state.ts @@ -7,6 +7,7 @@ */ import { Reference } from '@kbn/content-management-utils'; +import { MaybePromise } from '@kbn/utility-types'; /** * A package containing the serialized Embeddable state, with references extracted. When saving Embeddables using any @@ -17,10 +18,22 @@ export interface SerializedPanelState { rawState: RawStateType; } -export interface HasSerializableState { - serializeState: () => SerializedPanelState; +export interface HasSerializableState { + /** + * Serializes all state into a format that can be saved into + * some external store. The opposite of `deserialize` in the {@link ReactEmbeddableFactory} + */ + serializeState: () => MaybePromise>; } export const apiHasSerializableState = (api: unknown | null): api is HasSerializableState => { return Boolean((api as HasSerializableState)?.serializeState); }; + +export interface HasSnapshottableState { + /** + * Serializes all runtime state exactly as it appears. This could be used + * to rehydrate a component's state without needing to deserialize it. + */ + snapshotRuntimeState: () => RuntimeState; +} diff --git a/packages/presentation/presentation_containers/tsconfig.json b/packages/presentation/presentation_containers/tsconfig.json index 8e25a7b80c6e2..15fe397861700 100644 --- a/packages/presentation/presentation_containers/tsconfig.json +++ b/packages/presentation/presentation_containers/tsconfig.json @@ -10,5 +10,6 @@ "@kbn/presentation-publishing", "@kbn/core-mount-utils-browser", "@kbn/content-management-utils", + "@kbn/utility-types", ] } diff --git a/packages/presentation/presentation_publishing/index.ts b/packages/presentation/presentation_publishing/index.ts index c2669c19c3254..d1c3132e86c9f 100644 --- a/packages/presentation/presentation_publishing/index.ts +++ b/packages/presentation/presentation_publishing/index.ts @@ -29,16 +29,17 @@ export { useInheritedViewMode, type CanAccessViewMode, } from './interfaces/can_access_view_mode'; +export { fetch$, type FetchContext } from './interfaces/fetch/fetch'; export { initializeTimeRange, type SerializedTimeRange, } from './interfaces/fetch/initialize_time_range'; -export { fetch$, type FetchContext } from './interfaces/fetch/fetch'; export { apiPublishesPartialUnifiedSearch, apiPublishesTimeRange, apiPublishesUnifiedSearch, apiPublishesWritableUnifiedSearch, + useSearchApi, type PublishesTimeRange, type PublishesUnifiedSearch, type PublishesWritableUnifiedSearch, @@ -48,11 +49,21 @@ export { type HasAppContext, type EmbeddableAppContext, } from './interfaces/has_app_context'; -export { apiHasDisableTriggers, type HasDisableTriggers } from './interfaces/has_disable_triggers'; +export { + apiHasDisableTriggers, + areTriggersDisabled, + type HasDisableTriggers, +} from './interfaces/has_disable_triggers'; export { hasEditCapabilities, type HasEditCapabilities } from './interfaces/has_edit_capabilities'; +export { + apiHasExecutionContext, + type HasExecutionContext, +} from './interfaces/has_execution_context'; export { apiHasLegacyLibraryTransforms, apiHasLibraryTransforms, + apiHasInPlaceLibraryTransforms, + type HasInPlaceLibraryTransforms, type HasLegacyLibraryTransforms, type HasLibraryTransforms, } from './interfaces/has_library_transforms'; @@ -68,10 +79,6 @@ export { type HasTypeDisplayName, } from './interfaces/has_type'; export { apiHasUniqueId, type HasUniqueId } from './interfaces/has_uuid'; -export { - apiHasExecutionContext, - type HasExecutionContext, -} from './interfaces/has_execution_context'; export { apiPublishesBlockingError, type PublishesBlockingError, diff --git a/packages/presentation/presentation_publishing/interfaces/fetch/publishes_unified_search.ts b/packages/presentation/presentation_publishing/interfaces/fetch/publishes_unified_search.ts index 8aef4ceee6c30..5f349665fa36b 100644 --- a/packages/presentation/presentation_publishing/interfaces/fetch/publishes_unified_search.ts +++ b/packages/presentation/presentation_publishing/interfaces/fetch/publishes_unified_search.ts @@ -6,7 +6,9 @@ * Side Public License, v 1. */ +import { BehaviorSubject } from 'rxjs'; import { TimeRange, Filter, Query, AggregateQuery } from '@kbn/es-query'; +import { useEffect, useMemo } from 'react'; import { PublishingSubject } from '../../publishing_subject'; export interface PublishesTimeRange { @@ -68,3 +70,40 @@ export const apiPublishesWritableUnifiedSearch = ( typeof (unknownApi as PublishesWritableUnifiedSearch).setQuery === 'function' ); }; + +/** + * React hook that converts search props into search observable API + */ +export function useSearchApi({ + filters, + query, + timeRange, +}: { + filters?: Filter[]; + query?: Query | AggregateQuery; + timeRange?: TimeRange; +}) { + const searchApi = useMemo(() => { + return { + filters$: new BehaviorSubject(filters), + query$: new BehaviorSubject(query), + timeRange$: new BehaviorSubject(timeRange), + }; + // filters, query, timeRange only used as initial values. Changes do not effect memoized value + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + useEffect(() => { + searchApi.filters$.next(filters); + }, [filters, searchApi.filters$]); + + useEffect(() => { + searchApi.query$.next(query); + }, [query, searchApi.query$]); + + useEffect(() => { + searchApi.timeRange$.next(timeRange); + }, [timeRange, searchApi.timeRange$]); + + return searchApi; +} diff --git a/packages/presentation/presentation_publishing/interfaces/has_disable_triggers.ts b/packages/presentation/presentation_publishing/interfaces/has_disable_triggers.ts index 00066be3967fa..a4233faf2aab8 100644 --- a/packages/presentation/presentation_publishing/interfaces/has_disable_triggers.ts +++ b/packages/presentation/presentation_publishing/interfaces/has_disable_triggers.ts @@ -6,6 +6,8 @@ * Side Public License, v 1. */ +import { apiHasParentApi } from './has_parent_api'; + export interface HasDisableTriggers { disableTriggers: boolean; } @@ -13,3 +15,14 @@ export interface HasDisableTriggers { export const apiHasDisableTriggers = (api: unknown | null): api is HasDisableTriggers => { return Boolean(api && typeof (api as HasDisableTriggers).disableTriggers === 'boolean'); }; + +export function areTriggersDisabled(api?: unknown) { + function getDisabledTriggers(thisApi?: unknown) { + return apiHasDisableTriggers(thisApi) ? thisApi.disableTriggers : false; + } + + return ( + getDisabledTriggers(api) || + getDisabledTriggers(apiHasParentApi(api) ? api.parentApi : undefined) + ); +} diff --git a/packages/presentation/presentation_publishing/interfaces/has_library_transforms.ts b/packages/presentation/presentation_publishing/interfaces/has_library_transforms.ts index b3715c1b35ae2..17d48eca51be7 100644 --- a/packages/presentation/presentation_publishing/interfaces/has_library_transforms.ts +++ b/packages/presentation/presentation_publishing/interfaces/has_library_transforms.ts @@ -6,47 +6,93 @@ * Side Public License, v 1. */ -export interface HasLibraryTransforms { - // - // Add to library methods - // +import { PublishingSubject } from '../publishing_subject'; + +interface DuplicateTitleCheck { + checkForDuplicateTitle: ( + newTitle: string, + isTitleDuplicateConfirmed: boolean, + onTitleDuplicate: () => void + ) => Promise; +} +interface LibraryTransformGuards { /** * * @returns {Promise} * True when embeddable is by-value and can be converted to by-reference */ canLinkToLibrary: () => Promise; + /** + * + * @returns {Promise} + * True when embeddable is by-reference and can be converted to by-value + */ + canUnlinkFromLibrary: () => Promise; +} + +/** + * APIs that inherit this interface can be linked to and unlinked from the library in place without + * re-initialization. + */ +export interface HasInPlaceLibraryTransforms + extends Partial, + DuplicateTitleCheck { + /** + * The id of the library item that this embeddable is linked to. + */ + libraryId$: PublishingSubject; + /** * Save embeddable to library * * @returns {Promise} id of persisted library item */ saveToLibrary: (title: string) => Promise; + /** - * - * @returns {StateT} - * by-reference embeddable state replacing by-value embeddable state + * Un-links this embeddable from the library. This method is optional, and only needed if the Embeddable + * is not meant to be re-initialized as part of the unlink operation. If the embeddable needs to be re-initialized + * after unlinking, the getByValueState method should be used instead. */ - getByReferenceState: (libraryId: string) => StateT; - checkForDuplicateTitle: ( - newTitle: string, - isTitleDuplicateConfirmed: boolean, - onTitleDuplicate: () => void - ) => Promise; + unlinkFromLibrary: () => void; +} + +export const apiHasInPlaceLibraryTransforms = ( + unknownApi: null | unknown +): unknownApi is HasInPlaceLibraryTransforms => { + return Boolean( + unknownApi && + Boolean((unknownApi as HasInPlaceLibraryTransforms)?.libraryId$) && + typeof (unknownApi as HasInPlaceLibraryTransforms).saveToLibrary === 'function' && + typeof (unknownApi as HasInPlaceLibraryTransforms).unlinkFromLibrary === 'function' + ); +}; - // - // Unlink from library methods - // +/** + * APIs that inherit this interface can be linked to and unlinked from the library. After the save or unlink + * operation, the embeddable will be reinitialized. + */ +export interface HasLibraryTransforms + extends LibraryTransformGuards, + DuplicateTitleCheck { /** + * Save embeddable to library * - * @returns {Promise} - * True when embeddable is by-reference and can be converted to by-value + * @returns {Promise} id of persisted library item */ - canUnlinkFromLibrary: () => Promise; + saveToLibrary: (title: string) => Promise; + /** + * + * @returns {StateT} + * by-reference embeddable state replacing by-value embeddable state. After + * the save operation, the embeddable will be reinitialized with the results of this method. + */ + getByReferenceState: (libraryId: string) => StateT; /** * * @returns {StateT} - * by-value embeddable state replacing by-reference embeddable state + * by-value embeddable state replacing by-reference embeddable state. After + * the unlink operation, the embeddable will be reinitialized with the results of this method. */ getByValueState: () => StateT; } diff --git a/packages/shared-ux/chrome/navigation/__jest__/build_nav_tree.test.tsx b/packages/shared-ux/chrome/navigation/__jest__/build_nav_tree.test.tsx index 3a9fb5177135b..36e275ced131b 100644 --- a/packages/shared-ux/chrome/navigation/__jest__/build_nav_tree.test.tsx +++ b/packages/shared-ux/chrome/navigation/__jest__/build_nav_tree.test.tsx @@ -135,6 +135,40 @@ describe('builds navigation tree', () => { } }); + test('should allow custom onClick handler for links', async () => { + const navigateToUrl = jest.fn(); + const onClick = jest.fn(); + + const node: ChromeProjectNavigationNode = { + id: 'group1', + title: 'Group 1', + path: 'group1', + defaultIsCollapsed: false, + children: [ + { + id: 'item1', + title: 'Item 1', + href: 'https://foo', + path: 'group1.item1', + onClick, + }, + ], + }; + + const { findByTestId } = renderNavigation({ + navTreeDef: of({ + body: [node], + }), + services: { navigateToUrl }, + }); + + const navItem = await findByTestId(/nav-item-group1.item1\s/); + navItem.click(); + + expect(navigateToUrl).not.toHaveBeenCalled(); + expect(onClick).toHaveBeenCalledWith(expect.objectContaining({ type: 'click' })); + }); + test('should not render the group if it does not have children', async () => { const navTree: NavigationTreeDefinitionUI = { body: [ diff --git a/packages/shared-ux/chrome/navigation/src/ui/components/navigation_section_ui.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_section_ui.tsx index fe921f6bd0b73..1fc4601b50b91 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/components/navigation_section_ui.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_section_ui.tsx @@ -33,6 +33,7 @@ type EuiCollapsibleNavSubItemPropsEnhanced = EuiCollapsibleNavSubItemProps & { p const DEFAULT_SPACE_BETWEEN_LEVEL_1_GROUPS: EuiThemeSize = 'm'; const DEFAULT_IS_COLLAPSED = true; const DEFAULT_IS_COLLAPSIBLE = true; +const DEFAULT_RENDER_AS: RenderAs = 'block'; const nodeHasLink = (navNode: ChromeProjectNavigationNode) => Boolean(navNode.deepLink) || Boolean(navNode.href); @@ -62,7 +63,7 @@ const itemIsVisible = (item: ChromeProjectNavigationNode) => { const getRenderAs = (navNode: ChromeProjectNavigationNode): RenderAs => { if (navNode.renderAs) return navNode.renderAs; if (!navNode.children) return 'item'; - return 'block'; + return DEFAULT_RENDER_AS; }; const getTestSubj = (navNode: ChromeProjectNavigationNode, isActive = false): string => { @@ -155,6 +156,12 @@ const renderGroup = ( return [itemPrepend, ...groupItems]; }; +const isAccordionNode = ( + node: Pick +) => + node.renderAs === 'accordion' || + ['defaultIsCollapsed', 'isCollapsible'].some((prop) => node.hasOwnProperty(prop)); + // Generate the EuiCollapsible props for both the root component (EuiCollapsibleNavItem) and its // "items" props. Both are compatible with the exception of "renderItem" which is only used for // sub items. @@ -182,15 +189,30 @@ const nodeToEuiCollapsibleNavProps = ( isVisible: boolean; } => { const { navNode, isItem, hasChildren, hasLink } = serializeNavNode(_navNode); - const isActive = isActiveFromUrl(navNode.path, activeNodes); - - const { id, path, href, renderAs, isCollapsible = DEFAULT_IS_COLLAPSIBLE } = navNode; + const { + id, + path, + href, + renderAs, + onClick: customOnClick, + isCollapsible = DEFAULT_IS_COLLAPSIBLE, + } = navNode; + const isAccordion = isAccordionNode(navNode); + + // If the node is an accordion and it is not collapsible, we only want to mark it as active + // if it is the highest match in the URL, not if one of its children is also active. + const onlyIfHighestMatch = isAccordion && !isCollapsible; + const isActive = isActiveFromUrl(navNode.path, activeNodes, onlyIfHighestMatch); const isExternal = Boolean(href) && !navNode.isElasticInternalLink && isAbsoluteLink(href!); - - const isAccordion = hasChildren && !isItem; const isAccordionExpanded = (itemsAccordionState[path]?.isCollapsed ?? DEFAULT_IS_COLLAPSED) === false; - const isSelected = isAccordion && isAccordionExpanded ? false : isActive; + let isSelected = isActive; + + if (isAccordion && isAccordionExpanded) { + // For accordions that are collapsible, we don't want to mark the parent button as selected + // when it is expanded. If the accordion is **not** collapsible then we do. + isSelected = isCollapsible ? false : isActive; + } const dataTestSubj = getTestSubj(navNode, isSelected); @@ -221,7 +243,12 @@ const nodeToEuiCollapsibleNavProps = ( return { items, isVisible: true }; } - const onClick = (e: React.MouseEvent) => { + const onClick = (e: React.MouseEvent) => { + if (customOnClick) { + customOnClick(e); + return; + } + // Do not navigate if it is a collapsible accordion, link will be used in the breadcrumb if (isAccordion && isCollapsible) return; @@ -258,12 +285,14 @@ const nodeToEuiCollapsibleNavProps = ( ? { href, external: isExternal, - onClick: (e: React.MouseEvent) => { - // TODO: here we might want to toggle the accordion (if we "renderAs: 'accordion'") - // Will be done in following PR - e.preventDefault(); - e.stopPropagation(); + onClick: (e) => { + if (customOnClick) { + customOnClick(e); + return; + } + if (href) { + e.preventDefault(); navigateToUrl(href); } }, @@ -345,7 +374,14 @@ export const NavigationSectionUI: FC = React.memo(({ navNode: _navNode }) const { activeNodes } = useNavigation(); const { navigateToUrl, isSideNavCollapsed } = useServices(); - const { navNode } = useMemo(() => serializeNavNode(_navNode), [_navNode]); + const { navNode } = useMemo( + () => + serializeNavNode({ + renderAs: 'accordion', // Top level nodes are always rendered as accordion + ..._navNode, + }), + [_navNode] + ); const { open: openPanel, close: closePanel } = usePanel(); const navNodesById = useMemo(() => { @@ -367,7 +403,7 @@ export const NavigationSectionUI: FC = React.memo(({ navNode: _navNode }) const [itemsAccordionState, setItemsAccordionState] = useState(() => { return Object.entries(navNodesById).reduce((acc, [_id, node]) => { - if (node.children) { + if (isAccordionNode(node)) { let isCollapsed = DEFAULT_IS_COLLAPSED; let doCollapseFromActiveState = true; @@ -382,6 +418,7 @@ export const NavigationSectionUI: FC = React.memo(({ navNode: _navNode }) doCollapseFromActiveState, }; } + return acc; }, {}); }); @@ -390,14 +427,20 @@ export const NavigationSectionUI: FC = React.memo(({ navNode: _navNode }) const toggleAccordion = useCallback((id: string) => { setItemsAccordionState((prev) => { - // if (prev[id]?.isCollapsed === undefined) return prev; - const prevValue = prev[id]?.isCollapsed ?? DEFAULT_IS_COLLAPSED; + const prevState = prev[id]; + const prevValue = prevState?.isCollapsed ?? DEFAULT_IS_COLLAPSED; + const { isCollapsible } = prevState; return { ...prev, [id]: { ...prev[id], isCollapsed: !prevValue, - doCollapseFromActiveState: false, // once we manually toggle we don't want to auto-close it when URL changes + doCollapseFromActiveState: isCollapsible + ? // if the accordion is collapsible & the user has interacted with the accordion + // we don't want to auto-close it when URL changes to not interfere with the user's choice + false + : // if the accordion is **not** collapsible we do want to auto-close it when the URL changes + prevState.doCollapseFromActiveState, }, }; }); @@ -421,13 +464,16 @@ export const NavigationSectionUI: FC = React.memo(({ navNode: _navNode }) 'data-test-subj': classNames(`accordionArrow`, `accordionArrow-${id}`), }; - const updated: Partial = { + const updated: Partial = { ..._accordionProps, arrowProps, + isCollapsible, forceState, - onToggle: () => { - toggleAccordion(id); - }, + onToggle: isCollapsible + ? () => { + toggleAccordion(id); + } + : undefined, }; return updated; @@ -473,8 +519,7 @@ export const NavigationSectionUI: FC = React.memo(({ navNode: _navNode }) const prevState = prev[_id]; if ( - node.children && - node.renderAs !== 'item' && + isAccordionNode(node) && (!prevState || prevState.doCollapseFromActiveState === true) ) { let nextIsActive = false; @@ -523,7 +568,10 @@ export const NavigationSectionUI: FC = React.memo(({ navNode: _navNode }) items: serializeAccordionItems(item.items), accordionProps: item.items !== undefined - ? getAccordionProps(item.path ?? item.id!, item.accordionProps) + ? getAccordionProps(item.path ?? item.id!, { + onClick: item.onClick, + ...item.accordionProps, + }) : undefined, }; return parsed; diff --git a/packages/shared-ux/chrome/navigation/src/utils.test.ts b/packages/shared-ux/chrome/navigation/src/utils.test.ts new file mode 100644 index 0000000000000..3f73204c5a032 --- /dev/null +++ b/packages/shared-ux/chrome/navigation/src/utils.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 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 { isActiveFromUrl } from './utils'; + +describe('isActiveFromUrl()', () => { + test('returns true if the nodePath is active', () => { + const nodePath = 'path'; + const activeNodes = [[{ id: 'path', title: '', path: 'path' }]]; + expect(isActiveFromUrl(nodePath, activeNodes)).toBe(true); + }); + + test('returns true if the nodePath is active anywhere in the full path', () => { + const activeNodes = [ + [ + { id: 'path', title: '', path: 'parent' }, + { id: 'child', title: '', path: 'child' }, + ], + ]; + expect(isActiveFromUrl('parent', activeNodes)).toBe(true); // both parent + expect(isActiveFromUrl('child', activeNodes)).toBe(true); // and child are active + }); + + test('returns true only if the nodePath is highest match', () => { + const activeNodes = [ + [ + { id: 'path', title: '', path: 'parent' }, + { id: 'child', title: '', path: 'child' }, + ], + ]; + expect(isActiveFromUrl('parent', activeNodes, true)).toBe(false); // not parent + expect(isActiveFromUrl('child', activeNodes, true)).toBe(true); // and child are active + }); +}); diff --git a/packages/shared-ux/chrome/navigation/src/utils.ts b/packages/shared-ux/chrome/navigation/src/utils.ts index aa783235a6842..5b070c55176f0 100644 --- a/packages/shared-ux/chrome/navigation/src/utils.ts +++ b/packages/shared-ux/chrome/navigation/src/utils.ts @@ -19,8 +19,23 @@ function isSamePath(pathA: string | null, pathB: string | null) { return pathA === pathB; } -export function isActiveFromUrl(nodePath: string, activeNodes: ChromeProjectNavigationNode[][]) { +/** + * Predicate to check if a nodePath is active + * + * @param nodePath The path of the node to check + * @param activeNodes The active nodes to check against + * @param onlyIfHighestMatch Flag to indicate if we should only return true if the nodePath is the highest match + * @returns Boolean indicating if the nodePath is active + */ +export function isActiveFromUrl( + nodePath: string, + activeNodes: ChromeProjectNavigationNode[][], + onlyIfHighestMatch = false +) { return activeNodes.reduce((acc, nodesBranch) => { - return acc === true ? acc : nodesBranch.some((branch) => isSamePath(branch.path, nodePath)); + if (acc === true) return true; + return onlyIfHighestMatch + ? isSamePath(nodesBranch[nodesBranch.length - 1].path, nodePath) + : nodesBranch.some((branch) => isSamePath(branch.path, nodePath)); }, false); } diff --git a/packages/shared-ux/code_editor/impl/__snapshots__/code_editor.test.tsx.snap b/packages/shared-ux/code_editor/impl/__snapshots__/code_editor.test.tsx.snap index df22190992fb3..b4b4fea7b22fd 100644 --- a/packages/shared-ux/code_editor/impl/__snapshots__/code_editor.test.tsx.snap +++ b/packages/shared-ux/code_editor/impl/__snapshots__/code_editor.test.tsx.snap @@ -170,11 +170,13 @@ exports[` is rendered 1`] = ` isVisible={false} onBlur={[Function]} onFocus={[Function]} + onKeyDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} > @@ -250,6 +252,7 @@ exports[` is rendered 1`] = ` /> diff --git a/packages/solution-nav/es/README.md b/packages/solution-nav/es/README.md deleted file mode 100644 index 02c517e04ced5..0000000000000 --- a/packages/solution-nav/es/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# @kbn/solution-nav-es - -## This package contains the navigation definition for the Search solution in Kibana stateful. diff --git a/packages/solution-nav/es/definition.ts b/packages/solution-nav/es/definition.ts deleted file mode 100644 index 5ab4bb39c8a12..0000000000000 --- a/packages/solution-nav/es/definition.ts +++ /dev/null @@ -1,283 +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 { i18n } from '@kbn/i18n'; -import type { - SolutionNavigationDefinition, - NavigationTreeDefinition, -} from '@kbn/core-chrome-browser'; -import { of } from 'rxjs'; - -const title = i18n.translate('navigation.searchNav.headerSolutionSwitcher.searchSolutionTitle', { - defaultMessage: 'Search', -}); -const icon = 'logoElasticsearch'; - -const navTree: NavigationTreeDefinition = { - body: [ - { type: 'recentlyAccessed' }, - { - type: 'navGroup', - id: 'search_project_nav', - title, - icon, - defaultIsCollapsed: false, - isCollapsible: false, - breadcrumbStatus: 'hidden', - children: [ - { - link: 'enterpriseSearch', - }, - { - id: 'dev_tools', - title: i18n.translate('navigation.searchNav.devTools', { - defaultMessage: 'Dev Tools', - }), - link: 'dev_tools:console', - getIsActive: ({ pathNameSerialized, prepend }) => { - return pathNameSerialized.startsWith(prepend('/app/dev_tools')); - }, - }, - { - id: 'kibana', - title: i18n.translate('navigation.searchNav.kibana', { - defaultMessage: 'Kibana', - }), - children: [ - { - link: 'discover', - }, - { - link: 'dashboards', - getIsActive: ({ pathNameSerialized, prepend }) => { - return pathNameSerialized.startsWith(prepend('/app/dashboards')); - }, - }, - ], - }, - { - id: 'content', - title: i18n.translate('navigation.searchNav.content', { - defaultMessage: 'Content', - }), - children: [ - { - link: 'enterpriseSearchContent:searchIndices', - // TODO: Build the children dynamically - // https://github.com/elastic/kibana/issues/179751 - // renderAs: 'accordion', - // children: [ - // { - // title: i18n.translate( - // 'navigation.searchNav.content.indices.searchGithub.overview', - // { - // defaultMessage: 'Overview', - // } - // ), - // link: 'management:index_management', - // breadcrumbStatus: - // 'hidden' /* management sub-pages set their breadcrumbs themselves */, - // }, - // { - // title: i18n.translate( - // 'navigation.searchNav.content.indices.searchGithub.documents', - // { - // defaultMessage: 'Documents', - // } - // ), - // link: 'management:index_management', - // }, - // { - // title: i18n.translate( - // 'navigation.searchNav.content.indices.searchGithub.indexMappings', - // { - // defaultMessage: 'Index Mappings', - // } - // ), - // link: 'management:index_management', - // }, - // { - // title: i18n.translate( - // 'navigation.searchNav.content.indices.searchGithub.pipelines', - // { - // defaultMessage: 'Pipelines', - // } - // ), - // link: 'management:ingest_pipelines', - // }, - // ], - }, - { link: 'enterpriseSearchContent:connectors' }, - { link: 'enterpriseSearchContent:webCrawlers' }, - ], - }, - { - id: 'build', - title: i18n.translate('navigation.searchNav.build', { - defaultMessage: 'Build', - }), - children: [ - { - link: 'enterpriseSearchApplications:playground', - }, - { - title: i18n.translate('navigation.searchNav.build.searchApplications', { - defaultMessage: 'Search applications', - }), - link: 'enterpriseSearchApplications:searchApplications', - // TODO: Build the children dynamically - // https://github.com/elastic/kibana/issues/179751 - // renderAs: 'accordion', - // children: [ - // { - // title: i18n.translate( - // 'navigation.searchNav.build.searchApplications.docsExplorer', - // { - // defaultMessage: 'Docs explorer', - // } - // ), - // link: 'home', - // }, - // { - // title: i18n.translate('navigation.searchNav.build.searchApplications.content', { - // defaultMessage: 'Content', - // }), - // link: 'home', - // }, - // { - // title: i18n.translate('navigation.searchNav.build.searchApplications.connect', { - // defaultMessage: 'Connect', - // }), - // link: 'home', - // }, - // ], - }, - { - link: 'enterpriseSearchAnalytics', - }, - ], - }, - { - id: 'entsearch', - title: i18n.translate('navigation.searchNav.entsearch', { - defaultMessage: 'Enterprise Search', - }), - children: [ - { - title: i18n.translate('navigation.searchNav.entsearch.appSearch', { - defaultMessage: 'App Search', - }), - link: 'appSearch:engines', - getIsActive: ({ pathNameSerialized, prepend }) => { - return pathNameSerialized.startsWith(prepend('/app/enterprise_search/app_search')); - }, - }, - { - link: 'workplaceSearch', - }, - ], - }, - ], - }, - ], - footer: [ - { - type: 'navGroup', - id: 'project_settings_project_nav', - title: i18n.translate('navigation.searchNav.management', { - defaultMessage: 'Management', - }), - icon: 'gear', - breadcrumbStatus: 'hidden', - children: [ - { - title: i18n.translate('navigation.searchNav.management.trainedModels', { - defaultMessage: 'Trained models', - }), - link: 'ml:modelManagement', - }, - { - link: 'management', - title: i18n.translate('navigation.searchNav.mngt', { - defaultMessage: 'Stack Management', - }), - spaceBefore: null, - renderAs: 'panelOpener', - children: [ - { - title: 'Ingest', - children: [{ link: 'management:ingest_pipelines' }, { link: 'management:pipelines' }], - }, - { - title: 'Data', - children: [ - { link: 'management:index_management' }, - { link: 'management:index_lifecycle_management' }, - { link: 'management:snapshot_restore' }, - { link: 'management:rollup_jobs' }, - { link: 'management:transform' }, - { link: 'management:cross_cluster_replication' }, - { link: 'management:remote_clusters' }, - { link: 'management:migrate_data' }, - ], - }, - { - title: 'Alerts and Insights', - children: [ - { link: 'management:triggersActions' }, - { link: 'management:cases' }, - { link: 'management:triggersActionsConnectors' }, - { link: 'management:reporting' }, - { link: 'management:jobsListLink' }, - { link: 'management:watcher' }, - { link: 'management:maintenanceWindows' }, - ], - }, - { - title: 'Security', - children: [ - { link: 'management:users' }, - { link: 'management:roles' }, - { link: 'management:api_keys' }, - { link: 'management:role_mappings' }, - ], - }, - { - title: 'Kibana', - children: [ - { link: 'management:dataViews' }, - { link: 'management:filesManagement' }, - { link: 'management:objects' }, - { link: 'management:tags' }, - { link: 'management:search_sessions' }, - { link: 'management:aiAssistantManagementSelection' }, - { link: 'management:spaces' }, - { link: 'management:settings' }, - ], - }, - { - title: 'Stack', - children: [ - { link: 'management:license_management' }, - { link: 'management:upgrade_assistant' }, - ], - }, - ], - }, - ], - }, - ], -}; - -export const definition: SolutionNavigationDefinition = { - id: 'es', - title, - icon, - homePage: 'enterpriseSearch', - navigationTree$: of(navTree), -}; diff --git a/packages/solution-nav/es/kibana.jsonc b/packages/solution-nav/es/kibana.jsonc deleted file mode 100644 index ba8bb94cc1cbd..0000000000000 --- a/packages/solution-nav/es/kibana.jsonc +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "shared-common", - "id": "@kbn/solution-nav-es", - "owner": [ - "@elastic/appex-sharedux", - "@elastic/enterprise-search-frontend" - ] -} diff --git a/packages/solution-nav/es/package.json b/packages/solution-nav/es/package.json deleted file mode 100644 index a73bd66a9ddcc..0000000000000 --- a/packages/solution-nav/es/package.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "@kbn/solution-nav-es", - "private": true, - "version": "1.0.0", - "license": "SSPL-1.0 OR Elastic License 2.0" -} \ No newline at end of file diff --git a/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts b/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts index 015c517e9a6b8..08c1c039d5e79 100644 --- a/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts +++ b/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts @@ -112,7 +112,7 @@ describe('checking migration metadata changes on all registered SO types', () => "ingest-agent-policies": "803dc27e106440c41e8f3c3d8ee8bbb0821bcde2", "ingest-download-sources": "279a68147e62e4d8858c09ad1cf03bd5551ce58d", "ingest-outputs": "daafff49255ab700e07491376fe89f04fc998b91", - "ingest-package-policies": "e6da7d0ee2996241ade23b3a7811fe5d3e449cb2", + "ingest-package-policies": "44c682a6bf23993c665f0a60a427f3c120a0a10d", "ingest_manager_settings": "91445219e7115ff0c45d1dabd5d614a80b421797", "inventory-view": "b8683c8e352a286b4aca1ab21003115a4800af83", "kql-telemetry": "93c1d16c1a0dfca9c8842062cf5ef8f62ae401ad", @@ -138,7 +138,7 @@ describe('checking migration metadata changes on all registered SO types', () => "risk-engine-configuration": "aea0c371a462e6d07c3ceb3aff11891b47feb09d", "rules-settings": "892a2918ebaeba809a612b8d97cec0b07c800b5f", "sample-data-telemetry": "37441b12f5b0159c2d6d5138a494c9f440e950b5", - "search": "7598e4a701ddcaa5e3f44f22e797618a48595e6f", + "search": "4579401660a4089d5122b2fc8624825cb97b0480", "search-session": "b2fcd840e12a45039ada50b1355faeafa39876d1", "search-telemetry": "b568601618744720b5662946d3103e3fb75fe8ee", "security-rule": "07abb4d7e707d91675ec0495c73816394c7b521f", diff --git a/src/core/server/integration_tests/http/request.test.ts b/src/core/server/integration_tests/http/request.test.ts index 9e90c1364a902..e68bc9013ddfa 100644 --- a/src/core/server/integration_tests/http/request.test.ts +++ b/src/core/server/integration_tests/http/request.test.ts @@ -427,6 +427,7 @@ describe('KibanaRequest', () => { expect(resp3.body).toEqual({ requestId: 'gamma' }); }); }); + describe('request uuid', () => { it('generates a UUID', async () => { const { server: innerServer, createRouter } = await server.setup(setupDeps); @@ -442,4 +443,23 @@ describe('KibanaRequest', () => { expect(resp1.body.requestUuid).toBe('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'); }); }); + + describe('httpVersion and protocol', () => { + it('returns the correct values', async () => { + const { server: innerServer, createRouter } = await server.setup(setupDeps); + const router = createRouter('/'); + router.get({ path: '/', validate: false }, async (context, req, res) => { + return res.ok({ body: { httpVersion: req.httpVersion, protocol: req.protocol } }); + }); + await server.start(); + + const st = supertest(innerServer.listener); + + const resp1 = await st.get('/').expect(200); + expect(resp1.body).toEqual({ + httpVersion: '1.1', + protocol: 'http1', + }); + }); + }); }); diff --git a/src/core/server/integration_tests/http/set_tls_config.test.ts b/src/core/server/integration_tests/http/set_tls_config.test.ts index 6c198d820670f..b809a32075733 100644 --- a/src/core/server/integration_tests/http/set_tls_config.test.ts +++ b/src/core/server/integration_tests/http/set_tls_config.test.ts @@ -8,12 +8,7 @@ import supertest from 'supertest'; import { KBN_CERT_PATH, KBN_KEY_PATH, ES_KEY_PATH, ES_CERT_PATH } from '@kbn/dev-utils'; -import { - createServer, - getListenerOptions, - getServerOptions, - setTlsConfig, -} from '@kbn/server-http-tools'; +import { createServer, getServerOptions, setTlsConfig } from '@kbn/server-http-tools'; import { HttpConfig, config as httpConfig, @@ -47,8 +42,7 @@ describe('setTlsConfig', () => { const firstConfig = new HttpConfig(rawHttpConfig, CSP_CONFIG, EXTERNAL_URL_CONFIG); const serverOptions = getServerOptions(firstConfig); - const listenerOptions = getListenerOptions(firstConfig); - const server = createServer(serverOptions, listenerOptions); + const server = createServer(serverOptions); server.route({ method: 'GET', diff --git a/src/core/server/integration_tests/saved_objects/migrations/group2/multiple_kibana_nodes.test.ts b/src/core/server/integration_tests/saved_objects/migrations/group2/multiple_kibana_nodes.test.ts index 63abe75209d59..65fc3830ae069 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/group2/multiple_kibana_nodes.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/group2/multiple_kibana_nodes.test.ts @@ -176,13 +176,21 @@ describe('migration v2', () => { const startWithDelay = async (instances: Root[], delayInSec: number) => { const promises: Array> = []; + const errors: string[] = []; for (let i = 0; i < instances.length; i++) { - promises.push(instances[i].start()); + promises.push( + instances[i].start().catch((err) => { + errors.push(err.message); + }) + ); if (i < instances.length - 1) { await delay(delayInSec * 1000); } } - return Promise.all(promises); + await Promise.all(promises); + if (errors.length) { + throw new Error(`Failed to start all instances: ${errors.join(',')}`); + } }; it('migrates saved objects normally when multiple Kibana instances are started at the same time', async () => { diff --git a/src/dev/license_checker/config.ts b/src/dev/license_checker/config.ts index f73d44b46a982..a69a93bb8b351 100644 --- a/src/dev/license_checker/config.ts +++ b/src/dev/license_checker/config.ts @@ -86,7 +86,7 @@ export const LICENSE_OVERRIDES = { 'jsts@1.6.2': ['Eclipse Distribution License - v 1.0'], // cf. https://github.com/bjornharrtell/jsts '@mapbox/jsonlint-lines-primitives@2.0.2': ['MIT'], // license in readme https://github.com/tmcw/jsonlint '@elastic/ems-client@8.5.1': ['Elastic License 2.0'], - '@elastic/eui@94.3.0': ['SSPL-1.0 OR Elastic License 2.0'], + '@elastic/eui@94.5.1': ['SSPL-1.0 OR Elastic License 2.0'], 'language-subtag-registry@0.3.21': ['CC-BY-4.0'], // retired ODC‑By license https://github.com/mattcg/language-subtag-registry 'buffers@0.1.1': ['MIT'], // license in importing module https://www.npmjs.com/package/binary '@bufbuild/protobuf@1.2.1': ['Apache-2.0'], // license (Apache-2.0 AND BSD-3-Clause) diff --git a/src/plugins/console/public/application/containers/console_history/console_history.tsx b/src/plugins/console/public/application/containers/console_history/console_history.tsx index 6918f572ce916..3f8f071c98873 100644 --- a/src/plugins/console/public/application/containers/console_history/console_history.tsx +++ b/src/plugins/console/public/application/containers/console_history/console_history.tsx @@ -23,6 +23,7 @@ import { import { useServicesContext } from '../../contexts'; import { HistoryViewer } from './history_viewer'; +import { HistoryViewer as HistoryViewerMonaco } from './history_viewer_monaco'; import { useEditorReadContext } from '../../contexts/editor_context'; import { useRestoreRequestFromHistory } from '../../hooks'; @@ -35,6 +36,7 @@ const CHILD_ELEMENT_PREFIX = 'historyReq'; export function ConsoleHistory({ close }: Props) { const { services: { history }, + config: { isMonacoEnabled }, } = useServicesContext(); const { settings: readOnlySettings } = useEditorReadContext(); @@ -91,7 +93,7 @@ export function ConsoleHistory({ close }: Props) { initialize(); }; - const restoreRequestFromHistory = useRestoreRequestFromHistory(); + const restoreRequestFromHistory = useRestoreRequestFromHistory(isMonacoEnabled); useEffect(() => { initialize(); @@ -181,7 +183,11 @@ export function ConsoleHistory({ close }: Props) {
- + {isMonacoEnabled ? ( + + ) : ( + + )}
diff --git a/src/plugins/console/public/application/containers/console_history/history_viewer_monaco.tsx b/src/plugins/console/public/application/containers/console_history/history_viewer_monaco.tsx new file mode 100644 index 0000000000000..580dc863851f4 --- /dev/null +++ b/src/plugins/console/public/application/containers/console_history/history_viewer_monaco.tsx @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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, { useCallback, useRef } from 'react'; +import { css } from '@emotion/react'; +import { CONSOLE_LANG_ID, CONSOLE_THEME_ID, monaco } from '@kbn/monaco'; +import { CodeEditor } from '@kbn/code-editor'; +import { i18n } from '@kbn/i18n'; +import { formatRequestBodyDoc } from '../../../lib/utils'; +import { DevToolsSettings } from '../../../services'; +import { useResizeCheckerUtils } from '../editor/monaco/hooks'; + +export const HistoryViewer = ({ + settings, + req, +}: { + settings: DevToolsSettings; + req: { method: string; endpoint: string; data: string; time: string } | null; +}) => { + const divRef = useRef(null); + const { setupResizeChecker, destroyResizeChecker } = useResizeCheckerUtils(); + + const editorDidMountCallback = useCallback( + (editor: monaco.editor.IStandaloneCodeEditor) => { + setupResizeChecker(divRef.current!, editor); + }, + [setupResizeChecker] + ); + + const editorWillUnmountCallback = useCallback(() => { + destroyResizeChecker(); + }, [destroyResizeChecker]); + let renderedHistoryRequest: string; + if (req) { + const indent = true; + const formattedData = req.data ? formatRequestBodyDoc([req.data], indent).data : ''; + renderedHistoryRequest = req.method + ' ' + req.endpoint + '\n' + formattedData; + } else { + renderedHistoryRequest = i18n.translate('console.historyPage.noHistoryTextMessage', { + defaultMessage: 'No history available', + }); + } + return ( +
+ +
+ ); +}; diff --git a/src/plugins/console/public/application/containers/editor/monaco/hooks/index.ts b/src/plugins/console/public/application/containers/editor/monaco/hooks/index.ts index e0a56ebf655d0..93bc00bb4e8e7 100644 --- a/src/plugins/console/public/application/containers/editor/monaco/hooks/index.ts +++ b/src/plugins/console/public/application/containers/editor/monaco/hooks/index.ts @@ -10,3 +10,4 @@ export { useResizeCheckerUtils } from './use_resize_checker_utils'; export { useSetInitialValue } from './use_set_initial_value'; export { useSetupAutocompletePolling } from './use_setup_autocomplete_polling'; export { useSetupAutosave } from './use_setup_autosave'; +export { useKeyboardCommandsUtils } from './use_register_keyboard_commands'; diff --git a/src/plugins/console/public/application/containers/editor/monaco/hooks/use_register_keyboard_commands.ts b/src/plugins/console/public/application/containers/editor/monaco/hooks/use_register_keyboard_commands.ts new file mode 100644 index 0000000000000..9fff68bf13b2b --- /dev/null +++ b/src/plugins/console/public/application/containers/editor/monaco/hooks/use_register_keyboard_commands.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 { useRef } from 'react'; +import { i18n } from '@kbn/i18n'; +import { monaco } from '@kbn/monaco'; + +interface RegisterKeyboardCommandsParams { + /** The current Monaco editor instance. */ + editor: monaco.editor.IStandaloneCodeEditor; + /** Function for sending the selected request(s). */ + sendRequest: () => void; + /** Function for indenting the selected request(s). */ + autoIndent: () => void; + /** Function that returns the documentation link for the selected request. */ + getDocumentationLink: () => Promise | undefined; + /** Function for moving the cursor to the previous request edge. */ + moveToPreviousRequestEdge: () => void; + /** Function for moving the cursor to the next request edge. */ + moveToNextRequestEdge: () => void; +} + +const SEND_REQUEST_ACTION_ID = 'sendRequest'; +const AUTO_INDENT_ACTION_ID = 'autoIndent'; +const OPEN_DOCS_ACTION_ID = 'openDocs'; +const MOVE_UP_ACTION_ID = 'moveUp'; +const MOVE_DOWN_ACTION_ID = 'moveDown'; +const MOVE_TO_LINE_ACTION_ID = 'moveToLine'; + +/** + * Hook that returns a function for registering keyboard commands in the editor. + * + * @param params The {@link RegisterKeyboardCommandsParams} to use. + */ +export const useKeyboardCommandsUtils = () => { + const sendRequestAction = useRef(null); + const autoIndentAction = useRef(null); + const openDocsAction = useRef(null); + const moveToPreviousAction = useRef(null); + const moveToNextAction = useRef(null); + const moveToLineAction = useRef(null); + + const disposeAllActions = () => { + if (sendRequestAction.current) { + sendRequestAction.current.dispose(); + } + if (autoIndentAction.current) { + autoIndentAction.current.dispose(); + } + if (openDocsAction.current) { + openDocsAction.current.dispose(); + } + if (moveToPreviousAction.current) { + moveToPreviousAction.current.dispose(); + } + if (moveToNextAction.current) { + moveToNextAction.current.dispose(); + } + if (moveToLineAction.current) { + moveToLineAction.current.dispose(); + } + }; + + const registerKeyboardCommands = (params: RegisterKeyboardCommandsParams) => { + const { + editor, + sendRequest, + autoIndent, + getDocumentationLink, + moveToPreviousRequestEdge, + moveToNextRequestEdge, + } = params; + + const openDocs = async () => { + const documentation = await getDocumentationLink(); + if (!documentation) { + return; + } + window.open(documentation, '_blank'); + }; + + disposeAllActions(); + + sendRequestAction.current = editor.addAction({ + id: SEND_REQUEST_ACTION_ID, + label: i18n.translate('console.keyboardCommandActionLabel.sendRequest', { + defaultMessage: 'Send request', + }), + // eslint-disable-next-line no-bitwise + keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter], + run: sendRequest, + }); + + autoIndentAction.current = editor.addAction({ + id: AUTO_INDENT_ACTION_ID, + label: i18n.translate('console.keyboardCommandActionLabel.autoIndent', { + defaultMessage: 'Apply indentations', + }), + // eslint-disable-next-line no-bitwise + keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyI], + run: autoIndent, + }); + + openDocsAction.current = editor.addAction({ + id: OPEN_DOCS_ACTION_ID, + label: i18n.translate('console.keyboardCommandActionLabel.openDocs', { + defaultMessage: 'Open documentation', + }), + // eslint-disable-next-line no-bitwise + keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.Slash], + run: openDocs, + }); + + moveToPreviousAction.current = editor.addAction({ + id: MOVE_UP_ACTION_ID, + label: i18n.translate('console.keyboardCommandActionLabel.moveToPreviousRequestEdge', { + defaultMessage: 'Move to previous request start or end', + }), + // eslint-disable-next-line no-bitwise + keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.UpArrow], + run: moveToPreviousRequestEdge, + }); + + moveToNextAction.current = editor.addAction({ + id: MOVE_DOWN_ACTION_ID, + label: i18n.translate('console.keyboardCommandActionLabel.moveToNextRequestEdge', { + defaultMessage: 'Move to next request start or end', + }), + // eslint-disable-next-line no-bitwise + keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.DownArrow], + run: moveToNextRequestEdge, + }); + + moveToLineAction.current = editor.addAction({ + id: MOVE_TO_LINE_ACTION_ID, + label: i18n.translate('console.keyboardCommandActionLabel.moveToLine', { + defaultMessage: 'Move cursor to a line', + }), + // eslint-disable-next-line no-bitwise + keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyL], + run: () => { + const line = parseInt(prompt('Enter line number') ?? '', 10); + if (!isNaN(line)) { + editor.setPosition({ lineNumber: line, column: 1 }); + } + }, + }); + }; + + const unregisterKeyboardCommands = () => disposeAllActions(); + + return { registerKeyboardCommands, unregisterKeyboardCommands }; +}; diff --git a/src/plugins/console/public/application/containers/editor/monaco/hooks/use_set_initial_value.ts b/src/plugins/console/public/application/containers/editor/monaco/hooks/use_set_initial_value.ts index ccd45a3a98106..05a995e1625b0 100644 --- a/src/plugins/console/public/application/containers/editor/monaco/hooks/use_set_initial_value.ts +++ b/src/plugins/console/public/application/containers/editor/monaco/hooks/use_set_initial_value.ts @@ -30,6 +30,7 @@ interface SetInitialValueParams { /** * Util function for reading the load_from parameter from the current url. */ + export const readLoadFromParam = () => { const [, queryString] = (window.location.hash || window.location.search || '').split('?'); diff --git a/src/plugins/console/public/application/containers/editor/monaco/monaco_editor.tsx b/src/plugins/console/public/application/containers/editor/monaco/monaco_editor.tsx index 09da187694989..b54e6fa900b6e 100644 --- a/src/plugins/console/public/application/containers/editor/monaco/monaco_editor.tsx +++ b/src/plugins/console/public/application/containers/editor/monaco/monaco_editor.tsx @@ -12,6 +12,7 @@ import { css } from '@emotion/react'; import { CodeEditor } from '@kbn/code-editor'; import { CONSOLE_LANG_ID, CONSOLE_THEME_ID, monaco } from '@kbn/monaco'; import { i18n } from '@kbn/i18n'; +import { useSetInputEditor } from '../../../hooks'; import { ConsoleMenu } from '../../../components'; import { useServicesContext, @@ -23,6 +24,7 @@ import { useSetupAutocompletePolling, useSetupAutosave, useResizeCheckerUtils, + useKeyboardCommandsUtils, } from './hooks'; import { MonacoEditorActionsProvider } from './monaco_editor_actions_provider'; import { getSuggestionProvider } from './monaco_editor_suggestion_provider'; @@ -32,39 +34,23 @@ export interface EditorProps { } export const MonacoEditor = ({ initialTextValue }: EditorProps) => { + const context = useServicesContext(); const { - services: { - notifications, - esHostService, - trackUiMetric, - http, - settings: settingsService, - autocompleteInfo, - }, + services: { notifications, esHostService, settings: settingsService, autocompleteInfo }, docLinkVersion, - } = useServicesContext(); + } = context; const { toasts } = notifications; const { settings } = useEditorReadContext(); const divRef = useRef(null); const { setupResizeChecker, destroyResizeChecker } = useResizeCheckerUtils(); + const { registerKeyboardCommands, unregisterKeyboardCommands } = useKeyboardCommandsUtils(); const dispatch = useRequestActionContext(); const actionsProvider = useRef(null); const [editorActionsCss, setEditorActionsCss] = useState({}); - const editorDidMountCallback = useCallback( - (editor: monaco.editor.IStandaloneCodeEditor) => { - actionsProvider.current = new MonacoEditorActionsProvider(editor, setEditorActionsCss); - setupResizeChecker(divRef.current!, editor); - }, - [setupResizeChecker] - ); - - const editorWillUnmountCallback = useCallback(() => { - destroyResizeChecker(); - }, [destroyResizeChecker]); - + const setInputEditor = useSetInputEditor(); const getCurlCallback = useCallback(async (): Promise => { const curl = await actionsProvider.current?.getCurl(esHostService.getHost()); return curl ?? ''; @@ -79,8 +65,38 @@ export const MonacoEditor = ({ initialTextValue }: EditorProps) => { }, []); const sendRequestsCallback = useCallback(async () => { - await actionsProvider.current?.sendRequests(toasts, dispatch, trackUiMetric, http); - }, [dispatch, http, toasts, trackUiMetric]); + await actionsProvider.current?.sendRequests(dispatch, context); + }, [dispatch, context]); + + const editorDidMountCallback = useCallback( + (editor: monaco.editor.IStandaloneCodeEditor) => { + const provider = new MonacoEditorActionsProvider(editor, setEditorActionsCss); + setInputEditor(provider); + actionsProvider.current = provider; + setupResizeChecker(divRef.current!, editor); + registerKeyboardCommands({ + editor, + sendRequest: sendRequestsCallback, + autoIndent: async () => await actionsProvider.current?.autoIndent(), + getDocumentationLink: getDocumenationLink, + moveToPreviousRequestEdge: async () => + await actionsProvider.current?.moveToPreviousRequestEdge(), + moveToNextRequestEdge: async () => await actionsProvider.current?.moveToNextRequestEdge(), + }); + }, + [ + getDocumenationLink, + registerKeyboardCommands, + sendRequestsCallback, + setupResizeChecker, + setInputEditor, + ] + ); + + const editorWillUnmountCallback = useCallback(() => { + destroyResizeChecker(); + unregisterKeyboardCommands(); + }, [destroyResizeChecker, unregisterKeyboardCommands]); const suggestionProvider = useMemo(() => { return getSuggestionProvider(actionsProvider); diff --git a/src/plugins/console/public/application/containers/editor/monaco/monaco_editor_actions_provider.test.ts b/src/plugins/console/public/application/containers/editor/monaco/monaco_editor_actions_provider.test.ts index fb21900ddc292..b294b1d8de865 100644 --- a/src/plugins/console/public/application/containers/editor/monaco/monaco_editor_actions_provider.test.ts +++ b/src/plugins/console/public/application/containers/editor/monaco/monaco_editor_actions_provider.test.ts @@ -66,8 +66,11 @@ describe('Editor actions provider', () => { onDidChangeCursorSelection: jest.fn(), onDidContentSizeChange: jest.fn(), getSelection: jest.fn(), + getPosition: jest.fn(), getTopForLineNumber: jest.fn(), getScrollTop: jest.fn(), + executeEdits: jest.fn(), + setPosition: jest.fn(), } as unknown as jest.Mocked; editor.getModel.mockReturnValue({ @@ -210,4 +213,349 @@ describe('Editor actions provider', () => { expect((endpoints as string[]).sort()).toEqual(['_cat', '_search']); }); }); + + describe('move to next/previous request edge', () => { + beforeEach(() => { + /* The editor has the following text: + 1: + 2: POST _search + 3: { + 4: "test": "test" + 5: } + 6: GET _analyze + 7: + */ + mockGetParsedRequests.mockReturnValue([ + { + method: 'POST', + url: '_search', + startOffset: 1, + endOffset: 36, + data: [ + { + test: 'test', + }, + ], + }, + { + method: 'GET', + url: '_analyze', + startOffset: 37, + endOffset: 49, + }, + ]); + + editor.getModel.mockReturnValue({ + getPositionAt: (offset: number) => { + // mock for start offsets of the mocked requests + if (offset === 1) { + return { lineNumber: 2, column: 1 }; + } + if (offset === 37) { + return { lineNumber: 6, column: 1 }; + } + // mock for end offsets of the mocked requests + if (offset === 36) { + return { lineNumber: 5, column: 2 }; + } + if (offset === 49) { + return { lineNumber: 6, column: 13 }; + } + }, + getLineContent: (lineNumber: number) => { + if (lineNumber === 1) { + return ''; + } + if (lineNumber === 2) { + return 'POST _search'; + } + if (lineNumber === 3) { + return '{'; + } + if (lineNumber === 4) { + return ' "test": "test"'; + } + if (lineNumber === 5) { + return '}'; + } + if (lineNumber === 6) { + return 'GET _analyze'; + } + if (lineNumber === 7) { + return ''; + } + }, + getLineCount: () => 7, + } as unknown as monaco.editor.ITextModel); + }); + describe('moveToPreviousRequestEdge', () => { + it('correctly sets position when cursor is at first line of a request', async () => { + editor.getPosition.mockReturnValue({ + lineNumber: 6, + column: 4, + } as monaco.Position); + + await editorActionsProvider.moveToPreviousRequestEdge(); + expect(editor.setPosition).toHaveBeenCalledTimes(1); + expect(editor.setPosition).toHaveBeenCalledWith({ lineNumber: 5, column: 1 }); + }); + + it('correctly sets position when cursor is at last line of a request', async () => { + editor.getPosition.mockReturnValue({ + lineNumber: 5, + column: 1, + } as monaco.Position); + + await editorActionsProvider.moveToPreviousRequestEdge(); + expect(editor.setPosition).toHaveBeenCalledTimes(1); + expect(editor.setPosition).toHaveBeenCalledWith({ lineNumber: 2, column: 1 }); + }); + + it('correctly sets position when cursor is inside a request', async () => { + editor.getPosition.mockReturnValue({ + lineNumber: 4, + column: 1, + } as monaco.Position); + + await editorActionsProvider.moveToPreviousRequestEdge(); + expect(editor.setPosition).toHaveBeenCalledTimes(1); + expect(editor.setPosition).toHaveBeenCalledWith({ lineNumber: 2, column: 1 }); + }); + + it('correctly sets position when cursor is after a request', async () => { + editor.getPosition.mockReturnValue({ + lineNumber: 7, + column: 1, + } as monaco.Position); + + await editorActionsProvider.moveToPreviousRequestEdge(); + expect(editor.setPosition).toHaveBeenCalledTimes(1); + expect(editor.setPosition).toHaveBeenCalledWith({ lineNumber: 6, column: 1 }); + }); + + it('correctly sets position to first line of editor when there are no requests before cursor', async () => { + editor.getPosition.mockReturnValue({ + lineNumber: 2, + column: 3, + } as monaco.Position); + + await editorActionsProvider.moveToPreviousRequestEdge(); + expect(editor.setPosition).toHaveBeenCalledTimes(1); + expect(editor.setPosition).toHaveBeenCalledWith({ lineNumber: 1, column: 1 }); + }); + }); + + describe('moveToNextRequestEdge', () => { + it('correctly sets position when cursor is at first line of a request', async () => { + editor.getPosition.mockReturnValue({ + lineNumber: 2, + column: 8, + } as monaco.Position); + + await editorActionsProvider.moveToNextRequestEdge(); + expect(editor.setPosition).toHaveBeenCalledTimes(1); + expect(editor.setPosition).toHaveBeenCalledWith({ lineNumber: 5, column: 1 }); + }); + + it('correctly sets position when cursor is at last line of a request', async () => { + editor.getPosition.mockReturnValue({ + lineNumber: 5, + column: 1, + } as monaco.Position); + + await editorActionsProvider.moveToNextRequestEdge(); + expect(editor.setPosition).toHaveBeenCalledTimes(1); + expect(editor.setPosition).toHaveBeenCalledWith({ lineNumber: 6, column: 1 }); + }); + + it('correctly sets position when cursor is inside a request', async () => { + editor.getPosition.mockReturnValue({ + lineNumber: 3, + column: 1, + } as monaco.Position); + + await editorActionsProvider.moveToNextRequestEdge(); + expect(editor.setPosition).toHaveBeenCalledTimes(1); + expect(editor.setPosition).toHaveBeenCalledWith({ lineNumber: 5, column: 1 }); + }); + + it('correctly sets position when cursor is before a request', async () => { + editor.getPosition.mockReturnValue({ + lineNumber: 1, + column: 1, + } as monaco.Position); + + await editorActionsProvider.moveToNextRequestEdge(); + expect(editor.setPosition).toHaveBeenCalledTimes(1); + expect(editor.setPosition).toHaveBeenCalledWith({ lineNumber: 2, column: 1 }); + }); + + it('correctly sets position to last line of editor when there are no requests after cursor', async () => { + editor.getPosition.mockReturnValue({ + lineNumber: 6, + column: 3, + } as monaco.Position); + + await editorActionsProvider.moveToNextRequestEdge(); + expect(editor.setPosition).toHaveBeenCalledTimes(1); + expect(editor.setPosition).toHaveBeenCalledWith({ lineNumber: 7, column: 1 }); + }); + }); + }); + + describe('restoreRequestFromHistory', () => { + const testHistoryRequest = 'GET _alias'; + beforeEach(() => { + /* + * The editor has the text + * "POST _search" on line 1 + * { "test": "test" } on lines 2-4 + * and "GET _analyze" on line 5 + */ + mockGetParsedRequests.mockReturnValue([ + { + startOffset: 0, + method: 'POST', + url: '_search', + endOffset: 35, + data: [ + { + test: 'test', + }, + ], + }, + { + startOffset: 36, + method: 'GET', + url: '_analyze', + endOffset: 48, + }, + ]); + + editor.getModel.mockReturnValue({ + getLineMaxColumn: (lineNumber: number) => { + // mock this function for line 4 + return 2; + }, + getPositionAt: (offset: number) => { + // mock this function for start offsets of the mocked requests + if (offset === 0) { + return { lineNumber: 1, column: 1 }; + } + if (offset === 36) { + return { lineNumber: 5, column: 1 }; + } + // mock this function for end offsets of the mocked requests + if (offset === 35) { + return { lineNumber: 4, column: 2 }; + } + if (offset === 48) { + return { lineNumber: 5, column: 13 }; + } + }, + getLineContent: (lineNumber: number) => { + // mock this functions for line 1 and line 2 + if (lineNumber === 1) { + return 'POST _search'; + } + if (lineNumber === 2) { + return '{'; + } + if (lineNumber === 3) { + return ' "test": "test"'; + } + if (lineNumber === 4) { + return '}'; + } + if (lineNumber === 5) { + return 'GET _analyze'; + } + }, + } as unknown as monaco.editor.ITextModel); + }); + + it('insert the request at the beginning of the selected request', async () => { + // the position of the cursor is in the middle of line 5 + editor.getPosition.mockReturnValue({ + lineNumber: 5, + column: 4, + } as monaco.Position); + editor.getSelection.mockReturnValue({ + startLineNumber: 5, + endLineNumber: 5, + } as monaco.Selection); + + await editorActionsProvider.restoreRequestFromHistory(testHistoryRequest); + const expectedRange = { + startLineNumber: 5, + startColumn: 1, + endLineNumber: 5, + endColumn: 1, + }; + const expectedText = testHistoryRequest + '\n'; + const expectedEdit = { + range: expectedRange, + text: expectedText, + forceMoveMarkers: true, + }; + expect(editor.executeEdits).toHaveBeenCalledTimes(1); + expect(editor.executeEdits).toHaveBeenCalledWith('restoreFromHistory', [expectedEdit]); + }); + + it('insert the request at the end of the selected request', async () => { + // the position of the cursor is at the end of line 4 + editor.getPosition.mockReturnValue({ + lineNumber: 4, + column: 2, + } as monaco.Position); + editor.getSelection.mockReturnValue({ + startLineNumber: 4, + endLineNumber: 4, + } as monaco.Selection); + await editorActionsProvider.restoreRequestFromHistory(testHistoryRequest); + const expectedRange = { + startLineNumber: 4, + startColumn: 2, + endLineNumber: 4, + endColumn: 2, + }; + const expectedText = '\n' + testHistoryRequest; + const expectedEdit = { + range: expectedRange, + text: expectedText, + forceMoveMarkers: true, + }; + expect(editor.executeEdits).toHaveBeenCalledTimes(1); + expect(editor.executeEdits).toHaveBeenCalledWith('restoreFromHistory', [expectedEdit]); + }); + + it('insert at the beginning of the line, if no selected request', async () => { + // mock no parsed requests + mockGetParsedRequests.mockReturnValue([]); + // the position of the cursor is at the end of line 4 + editor.getPosition.mockReturnValue({ + lineNumber: 4, + column: 2, + } as monaco.Position); + editor.getSelection.mockReturnValue({ + startLineNumber: 4, + endLineNumber: 4, + } as monaco.Selection); + await editorActionsProvider.restoreRequestFromHistory(testHistoryRequest); + const expectedRange = { + startLineNumber: 4, + startColumn: 1, + endLineNumber: 4, + endColumn: 1, + }; + const expectedText = testHistoryRequest + '\n'; + const expectedEdit = { + range: expectedRange, + text: expectedText, + forceMoveMarkers: true, + }; + expect(editor.executeEdits).toHaveBeenCalledTimes(1); + expect(editor.executeEdits).toHaveBeenCalledWith('restoreFromHistory', [expectedEdit]); + }); + }); }); diff --git a/src/plugins/console/public/application/containers/editor/monaco/monaco_editor_actions_provider.ts b/src/plugins/console/public/application/containers/editor/monaco/monaco_editor_actions_provider.ts index de9c2289c8a29..dbb6dc1845e41 100644 --- a/src/plugins/console/public/application/containers/editor/monaco/monaco_editor_actions_provider.ts +++ b/src/plugins/console/public/application/containers/editor/monaco/monaco_editor_actions_provider.ts @@ -9,13 +9,12 @@ import { CSSProperties, Dispatch } from 'react'; import { debounce } from 'lodash'; import { ConsoleParsedRequestsProvider, getParsedRequestsProvider, monaco } from '@kbn/monaco'; -import { IToasts } from '@kbn/core-notifications-browser'; import { i18n } from '@kbn/i18n'; -import type { HttpSetup } from '@kbn/core-http-browser'; +import { toMountPoint } from '@kbn/react-kibana-mount'; +import { isQuotaExceededError } from '../../../../services/history'; import { DEFAULT_VARIABLES } from '../../../../../common/constants'; import { getStorage, StorageKeys } from '../../../../services'; import { sendRequest } from '../../../hooks'; -import { MetricsTracker } from '../../../../types'; import { Actions } from '../../../stores/request'; import { @@ -38,6 +37,8 @@ import { } from './utils'; import type { AdjustedParsedRequest } from './types'; +import { StorageQuotaError } from '../../../components/storage_quota_error'; +import { ContextValue } from '../../../contexts'; const AUTO_INDENTATION_ACTION_LABEL = 'Apply indentations'; @@ -180,12 +181,12 @@ export class MonacoEditorActionsProvider { return curlRequests.join('\n'); } - public async sendRequests( - toasts: IToasts, - dispatch: Dispatch, - trackUiMetric: MetricsTracker, - http: HttpSetup - ): Promise { + public async sendRequests(dispatch: Dispatch, context: ContextValue): Promise { + const { + services: { notifications, trackUiMetric, http, settings, history, autocompleteInfo }, + startServices, + } = context; + const { toasts } = notifications; try { const requests = await this.getRequests(); if (!requests.length) { @@ -205,8 +206,63 @@ export class MonacoEditorActionsProvider { const results = await sendRequest({ http, requests }); - // TODO save to history - // TODO restart autocomplete polling + let saveToHistoryError: undefined | Error; + const isHistoryEnabled = settings.getIsHistoryEnabled(); + + if (isHistoryEnabled) { + results.forEach(({ request: { path, method, data } }) => { + try { + history.addToHistory(path, method, data); + } catch (e) { + // Grab only the first error + if (!saveToHistoryError) { + saveToHistoryError = e; + } + } + }); + + if (saveToHistoryError) { + const errorTitle = i18n.translate('console.notification.error.couldNotSaveRequestTitle', { + defaultMessage: 'Could not save request to Console history.', + }); + if (isQuotaExceededError(saveToHistoryError)) { + const toast = notifications.toasts.addWarning({ + title: i18n.translate('console.notification.error.historyQuotaReachedMessage', { + defaultMessage: + 'Request history is full. Clear the console history or disable saving new requests.', + }), + text: toMountPoint( + StorageQuotaError({ + onClearHistory: () => { + history.clearHistory(); + notifications.toasts.remove(toast); + }, + onDisableSavingToHistory: () => { + settings.setIsHistoryEnabled(false); + notifications.toasts.remove(toast); + }, + }), + startServices + ), + }); + } else { + // Best effort, but still notify the user. + notifications.toasts.addError(saveToHistoryError, { + title: errorTitle, + }); + } + } + } + + const polling = settings.getPolling(); + if (polling) { + // If the user has submitted a request against ES, something in the fields, indices, aliases, + // or templates may have changed, so we'll need to update this data. Assume that if + // the user disables polling they're trying to optimize performance or otherwise + // preserve resources, so they won't want this request sent either. + autocompleteInfo.retrieve(settings, settings.getAutocomplete()); + } + dispatch({ type: 'requestSuccess', payload: { @@ -347,6 +403,54 @@ export class MonacoEditorActionsProvider { return this.getSuggestions(model, position, context); } + /* + * This function inserts a request from the history into the editor + */ + public async restoreRequestFromHistory(request: string) { + const model = this.editor.getModel(); + if (!model) { + return; + } + let position = this.editor.getPosition() as monaco.IPosition; + const requests = await this.getSelectedParsedRequests(); + let prefix = ''; + let suffix = ''; + // if there are requests at the cursor/selection, insert either before or after + if (requests.length > 0) { + // if on the 1st line of the 1st request, insert at the beginning of that line + if (position && position.lineNumber === requests[0].startLineNumber) { + position = { column: 1, lineNumber: position.lineNumber }; + suffix = '\n'; + } else { + // otherwise insert at the end of the last line of the last request + const lastLineNumber = requests[requests.length - 1].endLineNumber; + position = { column: model.getLineMaxColumn(lastLineNumber), lineNumber: lastLineNumber }; + prefix = '\n'; + } + } else { + // if not inside a request, insert the request at the cursor line + if (position) { + // insert at the beginning of the cursor line + position = { lineNumber: position.lineNumber, column: 1 }; + } else { + // otherwise insert on line 1 + position = { lineNumber: 1, column: 1 }; + } + suffix = '\n'; + } + const edit: monaco.editor.IIdentifiedSingleEditOperation = { + range: { + startLineNumber: position.lineNumber, + startColumn: position.column, + endLineNumber: position.lineNumber, + endColumn: position.column, + }, + text: prefix + request + suffix, + forceMoveMarkers: true, + }; + this.editor.executeEdits('restoreFromHistory', [edit]); + } + /* This function returns the text in the provided range. If no range is provided, it returns all text in the editor. @@ -399,4 +503,66 @@ export class MonacoEditorActionsProvider { }, ]); } + + /** + * This function moves the cursor to the previous request edge (start/end line). + * If the cursor is inside a request, it is moved to the start line of this request. + * If there are no requests before the cursor, it is moved at the first line in the editor. + */ + public async moveToPreviousRequestEdge() { + const currentPosition = this.editor.getPosition(); + const model = this.editor.getModel(); + if (!currentPosition || !model) { + return; + } + const { lineNumber: currentLineNumber } = currentPosition; + // Get all requests before the current line + const requestsBefore = await this.getRequestsBetweenLines(model, 1, currentLineNumber - 1); + if (requestsBefore.length === 0) { + // If no requests before current line, set position to first line + this.editor.setPosition({ lineNumber: 1, column: 1 }); + return; + } + const lastRequestBefore = requestsBefore[requestsBefore.length - 1]; + if (lastRequestBefore.endLineNumber < currentLineNumber) { + this.editor.setPosition({ lineNumber: lastRequestBefore.endLineNumber, column: 1 }); + } else { + // If the end line of the request is after the current line, then the cursor is inside the request + // The previous request edge is the start line of the request + this.editor.setPosition({ lineNumber: lastRequestBefore.startLineNumber, column: 1 }); + } + } + + /** + * This function moves the cursor to the next request edge. + * If the cursor is inside a request, it is moved to the end line of this request. + * If there are no requests after the cursor, it is moved at the last line in the editor. + */ + public async moveToNextRequestEdge() { + const currentPosition = this.editor.getPosition(); + const model = this.editor.getModel(); + if (!currentPosition || !model) { + return; + } + const { lineNumber: currentLineNumber } = currentPosition; + // Get all requests before the current line + const requestsAfter = await this.getRequestsBetweenLines( + model, + currentLineNumber + 1, + model.getLineCount() + ); + if (requestsAfter.length === 0) { + // If no requests after current line, set position to last line + this.editor.setPosition({ lineNumber: model.getLineCount(), column: 1 }); + return; + } + const firstRequestAfter = requestsAfter[0]; + if (firstRequestAfter.startLineNumber > currentLineNumber) { + this.editor.setPosition({ lineNumber: firstRequestAfter.startLineNumber, column: 1 }); + } else { + // If the start line of the request is before the current line, then the cursor is inside the request + // The next request edge is the end line of the request + this.editor.setPosition({ lineNumber: firstRequestAfter.endLineNumber, column: 1 }); + } + } } diff --git a/src/plugins/console/public/application/containers/editor/monaco/utils/autocomplete_utils.ts b/src/plugins/console/public/application/containers/editor/monaco/utils/autocomplete_utils.ts index 75a46590143c4..5302bf90d82c0 100644 --- a/src/plugins/console/public/application/containers/editor/monaco/utils/autocomplete_utils.ts +++ b/src/plugins/console/public/application/containers/editor/monaco/utils/autocomplete_utils.ts @@ -308,7 +308,6 @@ const getInsertText = ( } else { templateLines = JSON.stringify(template, null, 2).split(newLineRegex); } - // TODO add correct indentation insertText += ': ' + templateLines.join('\n'); } else if (value === '{') { insertText += '{}'; diff --git a/src/plugins/console/public/application/containers/embeddable/console_wrapper.tsx b/src/plugins/console/public/application/containers/embeddable/console_wrapper.tsx index db3624db41f68..7921e128721b6 100644 --- a/src/plugins/console/public/application/containers/embeddable/console_wrapper.tsx +++ b/src/plugins/console/public/application/containers/embeddable/console_wrapper.tsx @@ -107,29 +107,28 @@ interface ConsoleWrapperProps 'setDispatch' | 'alternateView' | 'setConsoleHeight' | 'getConsoleHeight' > { onKeyDown: (this: Window, ev: WindowEventMap['keydown']) => any; + isOpen: boolean; } export const ConsoleWrapper = (props: ConsoleWrapperProps) => { const [dependencies, setDependencies] = useState(null); - const { core, usageCollection, onKeyDown, isMonacoEnabled } = props; + const { core, usageCollection, onKeyDown, isMonacoEnabled, isOpen } = props; const { analytics, i18n, theme } = core; const startServices = { analytics, i18n, theme }; useEffect(() => { - if (dependencies === null) { + if (dependencies === null && isOpen) { loadDependencies(core, usageCollection).then(setDependencies); } - }, [dependencies, setDependencies, core, usageCollection]); + }, [dependencies, setDependencies, core, usageCollection, isOpen]); - useEffect(() => { - return () => { - if (dependencies) { - dependencies.autocompleteInfo.clearSubscriptions(); - } - }; - }, [dependencies]); + if (!dependencies && !isOpen) { + // Console has not been opened + return null; + } if (!dependencies) { + // Console open for the first time, wait for dependencies to load. return ; } @@ -171,10 +170,14 @@ export const ConsoleWrapper = (props: ConsoleWrapperProps) => { > -
- -
-
+ {isOpen ? ( +
+ +
+
+ ) : ( + + )}
diff --git a/src/plugins/console/public/application/containers/embeddable/embeddable_console.tsx b/src/plugins/console/public/application/containers/embeddable/embeddable_console.tsx index 42a6c4b0efb92..e8cddbf6d7364 100644 --- a/src/plugins/console/public/application/containers/embeddable/embeddable_console.tsx +++ b/src/plugins/console/public/application/containers/embeddable/embeddable_console.tsx @@ -190,8 +190,14 @@ export const EmbeddableConsole = ({ - {showConsole ? ( - + {consoleState.consoleHasBeenOpened ? ( + ) : null} {showAlternateView ? (
diff --git a/src/plugins/console/public/application/contexts/editor_context/editor_registry.ts b/src/plugins/console/public/application/contexts/editor_context/editor_registry.ts index 1b0c5a7b6bc1f..35e46a24c4821 100644 --- a/src/plugins/console/public/application/contexts/editor_context/editor_registry.ts +++ b/src/plugins/console/public/application/contexts/editor_context/editor_registry.ts @@ -6,12 +6,13 @@ * Side Public License, v 1. */ +import { MonacoEditorActionsProvider } from '../../containers/editor/monaco/monaco_editor_actions_provider'; import { SenseEditor } from '../../models/sense_editor'; export class EditorRegistry { - private inputEditor: SenseEditor | undefined; + private inputEditor: SenseEditor | MonacoEditorActionsProvider | undefined; - setInputEditor(inputEditor: SenseEditor) { + setInputEditor(inputEditor: SenseEditor | MonacoEditorActionsProvider) { this.inputEditor = inputEditor; } diff --git a/src/plugins/console/public/application/contexts/services_context.tsx b/src/plugins/console/public/application/contexts/services_context.tsx index 49bc4d4afec9b..89e7704023a09 100644 --- a/src/plugins/console/public/application/contexts/services_context.tsx +++ b/src/plugins/console/public/application/contexts/services_context.tsx @@ -30,7 +30,7 @@ export interface ContextValue { services: ContextServices; docLinkVersion: string; docLinks: DocLinksStart['links']; - config?: { + config: { isMonacoEnabled: boolean; }; startServices: ConsoleStartServices; diff --git a/src/plugins/console/public/application/hooks/use_restore_request_from_history/restore_request_from_history_to_monaco.ts b/src/plugins/console/public/application/hooks/use_restore_request_from_history/restore_request_from_history_to_monaco.ts new file mode 100644 index 0000000000000..67273a7b742d7 --- /dev/null +++ b/src/plugins/console/public/application/hooks/use_restore_request_from_history/restore_request_from_history_to_monaco.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 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 { formatRequestBodyDoc } from '../../../lib/utils'; +import { MonacoEditorActionsProvider } from '../../containers/editor/monaco/monaco_editor_actions_provider'; +import { ESRequest } from '../../../types'; + +export async function restoreRequestFromHistoryToMonaco( + provider: MonacoEditorActionsProvider, + req: ESRequest +) { + let s = req.method + ' ' + req.endpoint; + if (req.data) { + const indent = true; + const formattedData = formatRequestBodyDoc([req.data], indent); + s += '\n' + formattedData.data; + } + await provider.restoreRequestFromHistory(s); +} diff --git a/src/plugins/console/public/application/hooks/use_restore_request_from_history/use_restore_request_from_history.ts b/src/plugins/console/public/application/hooks/use_restore_request_from_history/use_restore_request_from_history.ts index 7c140e2b18975..05f3a2b6116ce 100644 --- a/src/plugins/console/public/application/hooks/use_restore_request_from_history/use_restore_request_from_history.ts +++ b/src/plugins/console/public/application/hooks/use_restore_request_from_history/use_restore_request_from_history.ts @@ -7,13 +7,23 @@ */ import { useCallback } from 'react'; +import { SenseEditor } from '../../models'; import { instance as registry } from '../../contexts/editor_context/editor_registry'; import { ESRequest } from '../../../types'; import { restoreRequestFromHistory } from './restore_request_from_history'; +import { restoreRequestFromHistoryToMonaco } from './restore_request_from_history_to_monaco'; +import { MonacoEditorActionsProvider } from '../../containers/editor/monaco/monaco_editor_actions_provider'; -export const useRestoreRequestFromHistory = () => { - return useCallback((req: ESRequest) => { - const editor = registry.getInputEditor(); - restoreRequestFromHistory(editor, req); - }, []); +export const useRestoreRequestFromHistory = (isMonacoEnabled: boolean) => { + return useCallback( + async (req: ESRequest) => { + const editor = registry.getInputEditor(); + if (isMonacoEnabled) { + await restoreRequestFromHistoryToMonaco(editor as MonacoEditorActionsProvider, req); + } else { + restoreRequestFromHistory(editor as SenseEditor, req); + } + }, + [isMonacoEnabled] + ); }; diff --git a/src/plugins/console/public/application/hooks/use_send_current_request/use_send_current_request.ts b/src/plugins/console/public/application/hooks/use_send_current_request/use_send_current_request.ts index 69f9042edd76d..723806d5c735b 100644 --- a/src/plugins/console/public/application/hooks/use_send_current_request/use_send_current_request.ts +++ b/src/plugins/console/public/application/hooks/use_send_current_request/use_send_current_request.ts @@ -19,6 +19,7 @@ import { track } from './track'; import { replaceVariables } from '../../../lib/utils'; import { StorageKeys } from '../../../services'; import { DEFAULT_VARIABLES } from '../../../../common/constants'; +import { SenseEditor } from '../../models'; export const useSendCurrentRequest = () => { const { @@ -30,7 +31,7 @@ export const useSendCurrentRequest = () => { return useCallback(async () => { try { - const editor = registry.getInputEditor(); + const editor = registry.getInputEditor() as SenseEditor; const variables = storage.get(StorageKeys.VARIABLES, DEFAULT_VARIABLES); let requests = await editor.getRequestsInRange(); requests = replaceVariables(requests, variables); @@ -47,7 +48,7 @@ export const useSendCurrentRequest = () => { dispatch({ type: 'sendRequest', payload: undefined }); // Fire and forget - setTimeout(() => track(requests, editor, trackUiMetric), 0); + setTimeout(() => track(requests, editor as SenseEditor, trackUiMetric), 0); const results = await sendRequest({ http, requests }); diff --git a/src/plugins/console/public/application/hooks/use_set_input_editor.ts b/src/plugins/console/public/application/hooks/use_set_input_editor.ts index c01dbbb0d2798..d2ac974cb18d8 100644 --- a/src/plugins/console/public/application/hooks/use_set_input_editor.ts +++ b/src/plugins/console/public/application/hooks/use_set_input_editor.ts @@ -10,12 +10,13 @@ import { useCallback } from 'react'; import { useEditorActionContext } from '../contexts/editor_context'; import { instance as registry } from '../contexts/editor_context/editor_registry'; import { SenseEditor } from '../models'; +import { MonacoEditorActionsProvider } from '../containers/editor/monaco/monaco_editor_actions_provider'; export const useSetInputEditor = () => { const dispatch = useEditorActionContext(); return useCallback( - (editor: SenseEditor) => { + (editor: SenseEditor | MonacoEditorActionsProvider) => { dispatch({ type: 'setInputEditor', payload: editor }); registry.setInputEditor(editor); }, diff --git a/src/plugins/console/public/application/stores/editor.ts b/src/plugins/console/public/application/stores/editor.ts index 3fdb0c3fd3422..e9496401ca611 100644 --- a/src/plugins/console/public/application/stores/editor.ts +++ b/src/plugins/console/public/application/stores/editor.ts @@ -12,6 +12,7 @@ import { identity } from 'fp-ts/lib/function'; import { DevToolsSettings, DEFAULT_SETTINGS } from '../../services'; import { TextObject } from '../../../common/text_object'; import { SenseEditor } from '../models'; +import { MonacoEditorActionsProvider } from '../containers/editor/monaco/monaco_editor_actions_provider'; export interface Store { ready: boolean; @@ -29,7 +30,7 @@ export const initialValue: Store = produce( ); export type Action = - | { type: 'setInputEditor'; payload: SenseEditor } + | { type: 'setInputEditor'; payload: SenseEditor | MonacoEditorActionsProvider } | { type: 'setCurrentTextObject'; payload: TextObject } | { type: 'updateSettings'; payload: DevToolsSettings }; diff --git a/src/plugins/console/public/application/stores/embeddable_console.ts b/src/plugins/console/public/application/stores/embeddable_console.ts index 26f1f78687250..3f2cf8261382f 100644 --- a/src/plugins/console/public/application/stores/embeddable_console.ts +++ b/src/plugins/console/public/application/stores/embeddable_console.ts @@ -18,6 +18,7 @@ import { export const initialValue: EmbeddedConsoleStore = produce( { + consoleHasBeenOpened: false, view: EmbeddableConsoleView.Closed, }, identity @@ -31,6 +32,7 @@ export const reducer: Reducer = (st ? EmbeddableConsoleView.Alternate : EmbeddableConsoleView.Console; if (state.view !== newView) { + draft.consoleHasBeenOpened = true; draft.view = newView; draft.loadFromContent = action.payload?.content; return draft; diff --git a/src/plugins/console/public/types/embeddable_console.ts b/src/plugins/console/public/types/embeddable_console.ts index 9a31e0f1cf151..0c4f6844edb6e 100644 --- a/src/plugins/console/public/types/embeddable_console.ts +++ b/src/plugins/console/public/types/embeddable_console.ts @@ -31,6 +31,7 @@ export enum EmbeddableConsoleView { } export interface EmbeddedConsoleStore { + consoleHasBeenOpened: boolean; view: EmbeddableConsoleView; loadFromContent?: string; } diff --git a/src/plugins/dashboard/public/dashboard_actions/add_to_library_action.tsx b/src/plugins/dashboard/public/dashboard_actions/add_to_library_action.tsx index 90a0667a87c5a..8f8178aa1e11c 100644 --- a/src/plugins/dashboard/public/dashboard_actions/add_to_library_action.tsx +++ b/src/plugins/dashboard/public/dashboard_actions/add_to_library_action.tsx @@ -23,6 +23,8 @@ import { HasParentApi, apiHasUniqueId, apiHasParentApi, + HasInPlaceLibraryTransforms, + apiHasInPlaceLibraryTransforms, } from '@kbn/presentation-publishing'; import { OnSaveProps, @@ -40,14 +42,14 @@ export const ACTION_ADD_TO_LIBRARY = 'saveToLibrary'; export type AddPanelToLibraryActionApi = CanAccessViewMode & HasType & HasUniqueId & - HasLibraryTransforms & + (HasLibraryTransforms | HasInPlaceLibraryTransforms) & HasParentApi> & Partial; const isApiCompatible = (api: unknown | null): api is AddPanelToLibraryActionApi => Boolean( apiCanAccessViewMode(api) && - apiHasLibraryTransforms(api) && + (apiHasLibraryTransforms(api) || apiHasInPlaceLibraryTransforms(api)) && apiHasType(api) && apiHasUniqueId(api) && apiHasParentApi(api) && @@ -79,7 +81,7 @@ export class AddToLibraryAction implements Action { public async isCompatible({ embeddable }: EmbeddableApiContext) { if (!isApiCompatible(embeddable)) return false; - return getInheritedViewMode(embeddable) === 'edit' && (await embeddable.canLinkToLibrary()); + return getInheritedViewMode(embeddable) === 'edit' && (await this.canLinkToLibrary(embeddable)); } public async execute({ embeddable }: EmbeddableApiContext) { @@ -87,7 +89,7 @@ export class AddToLibraryAction implements Action { const title = getPanelTitle(embeddable); try { - const byRefState = await new Promise((resolve, reject) => { + const byRefState = await new Promise((resolve, reject) => { const onSave = async (props: OnSaveProps): Promise => { await embeddable.checkForDuplicateTitle( props.newTitle, @@ -96,7 +98,10 @@ export class AddToLibraryAction implements Action { ); try { const libraryId = await embeddable.saveToLibrary(props.newTitle); - resolve({ ...embeddable.getByReferenceState(libraryId), title: props.newTitle }); + if (apiHasLibraryTransforms(embeddable)) { + resolve({ ...embeddable.getByReferenceState(libraryId), title: props.newTitle }); + } + resolve(undefined); return { id: libraryId }; } catch (error) { reject(error); @@ -118,10 +123,16 @@ export class AddToLibraryAction implements Action { /> ); }); - await embeddable.parentApi.replacePanel(embeddable.uuid, { - panelType: embeddable.type, - initialState: byRefState, - }); + /** + * If byRefState is defined, this embeddable type must be re-initialized with the + * newly provided state. + */ + if (byRefState) { + await embeddable.parentApi.replacePanel(embeddable.uuid, { + panelType: embeddable.type, + initialState: byRefState, + }); + } this.toastsService.addSuccess({ title: dashboardAddToLibraryActionStrings.getSuccessMessage(title ? `'${title}'` : ''), 'data-test-subj': 'addPanelToLibrarySuccess', @@ -133,4 +144,14 @@ export class AddToLibraryAction implements Action { }); } } + + private async canLinkToLibrary(api: AddPanelToLibraryActionApi) { + if (apiHasLibraryTransforms(api)) { + return api.canLinkToLibrary?.(); + } else if (apiHasInPlaceLibraryTransforms(api)) { + const canLink = api.canLinkToLibrary ? await api.canLinkToLibrary() : true; + return api.libraryId$.value === undefined && canLink; + } + throw new IncompatibleActionError(); + } } diff --git a/src/plugins/dashboard/public/dashboard_actions/library_notification_action.tsx b/src/plugins/dashboard/public/dashboard_actions/library_notification_action.tsx index 86adbab9c2030..ca4b20ae71433 100644 --- a/src/plugins/dashboard/public/dashboard_actions/library_notification_action.tsx +++ b/src/plugins/dashboard/public/dashboard_actions/library_notification_action.tsx @@ -9,14 +9,16 @@ import React from 'react'; import { + apiHasInPlaceLibraryTransforms, EmbeddableApiContext, getInheritedViewMode, getViewModeSubject, } from '@kbn/presentation-publishing'; import { Action, IncompatibleActionError } from '@kbn/ui-actions-plugin/public'; +import { BehaviorSubject, combineLatest } from 'rxjs'; import { LibraryNotificationPopover } from './library_notification_popover'; -import { dashboardLibraryNotificationStrings } from './_dashboard_actions_strings'; import { isApiCompatible, UnlinkFromLibraryAction } from './unlink_from_library_action'; +import { dashboardLibraryNotificationStrings } from './_dashboard_actions_strings'; export const ACTION_LIBRARY_NOTIFICATION = 'ACTION_LIBRARY_NOTIFICATION'; @@ -37,22 +39,27 @@ export class LibraryNotificationAction implements Action { return isApiCompatible(embeddable); } - public subscribeToCompatibilityChanges( + public subscribeToCompatibilityChanges = ( { embeddable }: EmbeddableApiContext, onChange: (isCompatible: boolean, action: LibraryNotificationAction) => void - ) { + ) => { if (!isApiCompatible(embeddable)) return; + const libraryIdSubject = apiHasInPlaceLibraryTransforms(embeddable) + ? embeddable.libraryId$ + : new BehaviorSubject(undefined); + const viewModeSubject = getViewModeSubject(embeddable); + if (!viewModeSubject) throw new IncompatibleActionError(); /** * TODO: Upgrade this action by subscribing to changes in the existance of a saved object id. Currently, * this is unnecessary because a link or unlink operation will cause the panel to unmount and remount. */ - return getViewModeSubject(embeddable)?.subscribe((viewMode) => { - embeddable.canUnlinkFromLibrary().then((canUnlink) => { + return combineLatest([libraryIdSubject, viewModeSubject]).subscribe(([libraryId, viewMode]) => { + this.unlinkAction.canUnlinkFromLibrary(embeddable).then((canUnlink) => { onChange(viewMode === 'edit' && canUnlink, this); }); }); - } + }; public getDisplayName({ embeddable }: EmbeddableApiContext) { if (!isApiCompatible(embeddable)) throw new IncompatibleActionError(); @@ -66,7 +73,10 @@ export class LibraryNotificationAction implements Action { public isCompatible = async ({ embeddable }: EmbeddableApiContext) => { if (!isApiCompatible(embeddable)) return false; - return getInheritedViewMode(embeddable) === 'edit' && embeddable.canUnlinkFromLibrary(); + return ( + getInheritedViewMode(embeddable) === 'edit' && + this.unlinkAction.canUnlinkFromLibrary(embeddable) + ); }; public execute = async () => {}; diff --git a/src/plugins/dashboard/public/dashboard_actions/library_notification_popover.tsx b/src/plugins/dashboard/public/dashboard_actions/library_notification_popover.tsx index bbb480d990f1d..6a11450d1b213 100644 --- a/src/plugins/dashboard/public/dashboard_actions/library_notification_popover.tsx +++ b/src/plugins/dashboard/public/dashboard_actions/library_notification_popover.tsx @@ -70,7 +70,10 @@ export function LibraryNotificationPopover({ unlinkAction, api }: LibraryNotific data-test-subj={'libraryNotificationUnlinkButton'} size="s" fill - onClick={() => unlinkAction.execute({ embeddable: api })} + onClick={() => { + setIsPopoverOpen(false); + unlinkAction.execute({ embeddable: api }); + }} > {unlinkAction.getDisplayName({ embeddable: api })} diff --git a/src/plugins/dashboard/public/dashboard_actions/unlink_from_library_action.tsx b/src/plugins/dashboard/public/dashboard_actions/unlink_from_library_action.tsx index cccfa64028ad2..17612fa9c6ef7 100644 --- a/src/plugins/dashboard/public/dashboard_actions/unlink_from_library_action.tsx +++ b/src/plugins/dashboard/public/dashboard_actions/unlink_from_library_action.tsx @@ -23,6 +23,8 @@ import { apiHasUniqueId, HasType, apiHasType, + HasInPlaceLibraryTransforms, + apiHasInPlaceLibraryTransforms, } from '@kbn/presentation-publishing'; import { PresentationContainer } from '@kbn/presentation-containers'; import { pluginServices } from '../services/plugin_services'; @@ -31,7 +33,7 @@ import { dashboardUnlinkFromLibraryActionStrings } from './_dashboard_actions_st export const ACTION_UNLINK_FROM_LIBRARY = 'unlinkFromLibrary'; export type UnlinkPanelFromLibraryActionApi = CanAccessViewMode & - HasLibraryTransforms & + (HasLibraryTransforms | HasInPlaceLibraryTransforms) & HasType & HasUniqueId & HasParentApi> & @@ -40,7 +42,7 @@ export type UnlinkPanelFromLibraryActionApi = CanAccessViewMode & export const isApiCompatible = (api: unknown | null): api is UnlinkPanelFromLibraryActionApi => Boolean( apiCanAccessViewMode(api) && - apiHasLibraryTransforms(api) && + (apiHasLibraryTransforms(api) || apiHasInPlaceLibraryTransforms(api)) && apiHasUniqueId(api) && apiHasType(api) && apiHasParentApi(api) && @@ -70,19 +72,40 @@ export class UnlinkFromLibraryAction implements Action { return 'folderExclamation'; } + public async canUnlinkFromLibrary(api: UnlinkPanelFromLibraryActionApi) { + if (apiHasLibraryTransforms(api)) { + return api.canUnlinkFromLibrary(); + } else if (apiHasInPlaceLibraryTransforms(api)) { + const canUnLink = api.canUnlinkFromLibrary ? await api.canUnlinkFromLibrary() : true; + return canUnLink && api.libraryId$.value !== undefined; + } + throw new IncompatibleActionError(); + } + public async isCompatible({ embeddable }: EmbeddableApiContext) { - if (!isApiCompatible(embeddable)) return false; - return getInheritedViewMode(embeddable) === 'edit' && (await embeddable.canUnlinkFromLibrary()); + if (!isApiCompatible(embeddable)) { + // either a an `unlinkFromLibrary` method or a `getByValueState` method is required + return false; + } + return ( + getInheritedViewMode(embeddable) === 'edit' && (await this.canUnlinkFromLibrary(embeddable)) + ); } public async execute({ embeddable }: EmbeddableApiContext) { if (!isApiCompatible(embeddable)) throw new IncompatibleActionError(); const title = getPanelTitle(embeddable); try { - await embeddable.parentApi.replacePanel(embeddable.uuid, { - panelType: embeddable.type, - initialState: { ...embeddable.getByValueState(), title }, - }); + if (apiHasLibraryTransforms(embeddable)) { + await embeddable.parentApi.replacePanel(embeddable.uuid, { + panelType: embeddable.type, + initialState: { ...embeddable.getByValueState(), title }, + }); + } else if (apiHasInPlaceLibraryTransforms(embeddable)) { + embeddable.unlinkFromLibrary(); + } else { + throw new IncompatibleActionError(); + } this.toastsService.addSuccess({ title: dashboardUnlinkFromLibraryActionStrings.getSuccessMessage(title ? `'${title}'` : ''), 'data-test-subj': 'unlinkPanelSuccess', diff --git a/src/plugins/dashboard/public/dashboard_app/top_nav/share/show_share_modal.test.tsx b/src/plugins/dashboard/public/dashboard_app/top_nav/share/show_share_modal.test.tsx index da4cb0b637398..9cdab72403e5b 100644 --- a/src/plugins/dashboard/public/dashboard_app/top_nav/share/show_share_modal.test.tsx +++ b/src/plugins/dashboard/public/dashboard_app/top_nav/share/show_share_modal.test.tsx @@ -70,7 +70,9 @@ describe('ShowShareModal', () => { const getPropsAndShare = ( unsavedState?: Partial ): ShowShareModalProps => { - pluginServices.getServices().dashboardBackup.getState = jest.fn().mockReturnValue(unsavedState); + pluginServices.getServices().dashboardBackup.getState = jest + .fn() + .mockReturnValue({ dashboardState: unsavedState }); return { isDirty: true, anchorElement: document.createElement('div'), diff --git a/src/plugins/dashboard/public/dashboard_app/top_nav/share/show_share_modal.tsx b/src/plugins/dashboard/public/dashboard_app/top_nav/share/show_share_modal.tsx index e654a8aad29e5..b60c389346638 100644 --- a/src/plugins/dashboard/public/dashboard_app/top_nav/share/show_share_modal.tsx +++ b/src/plugins/dashboard/public/dashboard_app/top_nav/share/show_share_modal.tsx @@ -23,7 +23,7 @@ import { DASHBOARD_APP_LOCATOR } from '@kbn/deeplinks-analytics'; import { dashboardUrlParams } from '../../dashboard_router'; import { shareModalStrings } from '../../_dashboard_app_strings'; import { pluginServices } from '../../../services/plugin_services'; -import { convertPanelMapToSavedPanels } from '../../../../common'; +import { convertPanelMapToSavedPanels, DashboardPanelMap } from '../../../../common'; import { DashboardLocatorParams } from '../../../dashboard_container'; const showFilterBarId = 'showFilterBar'; @@ -123,18 +123,23 @@ export function ShowShareModal({ }; let unsavedStateForLocator: DashboardLocatorParams = {}; - const unsavedDashboardState = dashboardBackup.getState(savedObjectId); + const { dashboardState: unsavedDashboardState, panels } = + dashboardBackup.getState(savedObjectId) ?? {}; + + const allPanels: DashboardPanelMap = { + ...(unsavedDashboardState?.panels ?? {}), + ...((panels as DashboardPanelMap) ?? {}), + }; if (unsavedDashboardState) { unsavedStateForLocator = { query: unsavedDashboardState.query, filters: unsavedDashboardState.filters, controlGroupInput: unsavedDashboardState.controlGroupInput as SerializableControlGroupInput, - panels: unsavedDashboardState.panels - ? (convertPanelMapToSavedPanels( - unsavedDashboardState.panels - ) as DashboardLocatorParams['panels']) - : undefined, + panels: + allPanels && Object.keys(allPanels).length > 0 + ? (convertPanelMapToSavedPanels(allPanels) as DashboardLocatorParams['panels']) + : undefined, // options useMargins: unsavedDashboardState?.useMargins, diff --git a/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.tsx b/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.tsx index 7ec73f6dbe97c..b0413b9fa3c46 100644 --- a/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.tsx +++ b/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.tsx @@ -13,7 +13,6 @@ import { PhaseEvent } from '@kbn/presentation-publishing'; import classNames from 'classnames'; import React, { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'; import { DashboardPanelState } from '../../../../common'; -import { getReferencesForPanelId } from '../../../../common/dashboard_container/persistable_state/dashboard_container_references'; import { pluginServices } from '../../../services/plugin_services'; import { useDashboardContainer } from '../../embeddable/dashboard_container'; @@ -52,7 +51,6 @@ export const Item = React.forwardRef( const scrollToPanelId = container.select((state) => state.componentState.scrollToPanelId); const highlightPanelId = container.select((state) => state.componentState.highlightPanelId); const useMargins = container.select((state) => state.explicitInput.useMargins); - const panel = container.select((state) => state.explicitInput.panels[id]); const expandPanel = expandedPanelId !== undefined && expandedPanelId === id; const hidePanel = expandedPanelId !== undefined && expandedPanelId !== id; @@ -99,7 +97,6 @@ export const Item = React.forwardRef( const { embeddable: { reactEmbeddableRegistryHasKey }, } = pluginServices.getServices(); - const references = getReferencesForPanelId(id, container.savedObjectReferences); const panelProps = { showBadges: true, @@ -114,11 +111,10 @@ export const Item = React.forwardRef( container} key={`${type}_${id}`} panelProps={panelProps} onApiAvailable={(api) => container.registerChildApi(api)} - state={{ rawState: panel.explicitInput as object, references }} /> ); } @@ -132,7 +128,7 @@ export const Item = React.forwardRef( {...panelProps} /> ); - }, [id, container, useMargins, type, index, onPanelStatusChange, panel.explicitInput]); + }, [id, container, type, index, useMargins, onPanelStatusChange]); return (
}> + > = []; for (const [uuid, panel] of Object.entries(panels)) { if (!reactEmbeddableRegistryHasKey(panel.type)) continue; const api = dashboard.children$.value[uuid]; + if (api && apiHasSerializableState(api)) { - const serializedState = api.serializeState(); - panels[uuid].explicitInput = { ...serializedState.rawState, id: uuid }; - references.push(...prefixReferencesFromPanel(uuid, serializedState.references ?? [])); + serializePromises.push( + (async () => { + const serialized = await api.serializeState(); + return { uuid, serialized }; + })() + ); } } + + const serializeResults = await Promise.all(serializePromises); + for (const result of serializeResults) { + panels[result.uuid].explicitInput = { ...result.serialized.rawState, id: result.uuid }; + references.push(...prefixReferencesFromPanel(result.uuid, result.serialized.references ?? [])); + } + return { panels, references }; }; @@ -145,7 +160,7 @@ export function runSaveAs(this: DashboardContainer) { }); } this.savedObjectReferences = saveResult.references ?? []; - this.lastSavedState.next(); + this.saveNotification$.next(); resolve(saveResult); return saveResult; }; @@ -199,7 +214,7 @@ export async function runQuickSave(this: DashboardContainer) { this.savedObjectReferences = saveResult.references ?? []; this.dispatch.setLastSavedInput(dashboardStateToSave); - this.lastSavedState.next(); + this.saveNotification$.next(); if (this.controlGroup && persistableControlGroupInput) { this.controlGroup.setSavedState(persistableControlGroupInput); } diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.test.ts b/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.test.ts index 12eebe31da173..bfe29801b07fb 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.test.ts +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.test.ts @@ -168,7 +168,7 @@ test('pulls state from backup which overrides state from saved object', async () }); pluginServices.getServices().dashboardBackup.getState = jest .fn() - .mockReturnValue({ description: 'wow this description marginally better' }); + .mockReturnValue({ dashboardState: { description: 'wow this description marginally better' } }); const dashboard = await createDashboard({ useSessionStorageIntegration: true }, 0, 'wow-such-id'); expect(dashboard).toBeDefined(); expect(dashboard!.getState().explicitInput.description).toBe( diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.ts b/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.ts index ac585ce58d8cc..cd0d5e6fa23df 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.ts +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/create/create_dashboard.ts @@ -195,11 +195,18 @@ export const initializeDashboard = async ({ // -------------------------------------------------------------------------------------- // Gather input from session storage and local storage if integration is used. // -------------------------------------------------------------------------------------- + const dashboardBackupState = dashboardBackup.getState(loadDashboardReturn.dashboardId); const sessionStorageInput = ((): Partial | undefined => { if (!useSessionStorageIntegration) return; - return dashboardBackup.getState(loadDashboardReturn.dashboardId); + return dashboardBackupState?.dashboardState; })(); + if (useSessionStorageIntegration) { + untilDashboardReady().then((dashboardContainer) => { + dashboardContainer.restoredRuntimeState = dashboardBackupState?.panels; + }); + } + // -------------------------------------------------------------------------------------- // Combine input from saved object, session storage, & passed input to create initial input. // -------------------------------------------------------------------------------------- diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx b/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx index 9a33543b7c3b1..a0a10469483c7 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx @@ -34,7 +34,12 @@ import { } from '@kbn/embeddable-plugin/public'; import type { Filter, Query, TimeRange } from '@kbn/es-query'; import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; -import { TrackContentfulRender } from '@kbn/presentation-containers'; +import { + HasRuntimeChildState, + HasSaveNotification, + HasSerializedChildState, + TrackContentfulRender, +} from '@kbn/presentation-containers'; import { apiHasSerializableState, PanelPackage } from '@kbn/presentation-containers'; import { ReduxEmbeddableTools, ReduxToolsPackage } from '@kbn/presentation-util-plugin/public'; import { LocatorPublic } from '@kbn/share-plugin/common'; @@ -72,6 +77,7 @@ import { DashboardPublicState, DashboardReduxState, DashboardRenderPerformanceStats, + UnsavedPanelState, } from '../types'; import { addFromLibrary, @@ -123,7 +129,12 @@ export const useDashboardContainer = (): DashboardContainer => { export class DashboardContainer extends Container - implements DashboardExternallyAccessibleApi, TrackContentfulRender + implements + DashboardExternallyAccessibleApi, + TrackContentfulRender, + HasSaveNotification, + HasRuntimeChildState, + HasSerializedChildState { public readonly type = DASHBOARD_CONTAINER_TYPE; @@ -575,7 +586,9 @@ export class DashboardContainer if (reactEmbeddableRegistryHasKey(panel.type)) { const child = this.children$.value[panelId]; if (!child) throw new PanelNotFoundError(); - const serialized = apiHasSerializableState(child) ? child.serializeState() : { rawState: {} }; + const serialized = apiHasSerializableState(child) + ? await child.serializeState() + : { rawState: {} }; return { type: panel.type, explicitInput: { ...panel.explicitInput, ...serialized.rawState }, @@ -806,17 +819,19 @@ export class DashboardContainer }); }; - public lastSavedState: Subject = new Subject(); - public getLastSavedStateForChild = (childId: string) => { - const { - componentState: { - lastSavedInput: { panels }, - }, - } = this.getState(); - const panel: DashboardPanelState | undefined = panels[childId]; + public saveNotification$: Subject = new Subject(); + public getSerializedStateForChild = (childId: string) => { const references = getReferencesForPanelId(childId, this.savedObjectReferences); - return { rawState: panel?.explicitInput, version: panel?.version, references }; + return { + rawState: this.getInput().panels[childId].explicitInput, + references, + }; + }; + + public restoredRuntimeState: UnsavedPanelState | undefined = undefined; + public getRuntimeStateForChild = (childId: string) => { + return this.restoredRuntimeState?.[childId]; }; public removePanel(id: string) { @@ -857,6 +872,7 @@ export class DashboardContainer }; public resetAllReactEmbeddables = () => { + this.restoredRuntimeState = undefined; let resetChangedPanelCount = false; const currentChildren = this.children$.value; for (const panelId of Object.keys(currentChildren)) { diff --git a/src/plugins/dashboard/public/dashboard_container/state/diffing/dashboard_diffing_integration.ts b/src/plugins/dashboard/public/dashboard_container/state/diffing/dashboard_diffing_integration.ts index a8644239de90e..dc3c4996e860f 100644 --- a/src/plugins/dashboard/public/dashboard_container/state/diffing/dashboard_diffing_integration.ts +++ b/src/plugins/dashboard/public/dashboard_container/state/diffing/dashboard_diffing_integration.ts @@ -8,7 +8,7 @@ import { PersistableControlGroupInput } from '@kbn/controls-plugin/common'; import { apiPublishesUnsavedChanges, PublishesUnsavedChanges } from '@kbn/presentation-publishing'; import deepEqual from 'fast-deep-equal'; -import { cloneDeep, omit } from 'lodash'; +import { omit } from 'lodash'; import { AnyAction, Middleware } from 'redux'; import { combineLatest, debounceTime, Observable, of, startWith, switchMap } from 'rxjs'; import { distinctUntilChanged, map } from 'rxjs'; @@ -16,6 +16,7 @@ import { DashboardContainer, DashboardCreationOptions } from '../..'; import { DashboardContainerInput } from '../../../../common'; import { CHANGE_CHECK_DEBOUNCE } from '../../../dashboard_constants'; import { pluginServices } from '../../../services/plugin_services'; +import { UnsavedPanelState } from '../../types'; import { dashboardContainerReducers } from '../dashboard_container_reducers'; import { isKeyEqualAsync, unsavedChangesDiffingFunctions } from './dashboard_diffing_functions'; @@ -151,13 +152,17 @@ export function startDiffingDashboardState( this.dispatch.setHasUnsavedChanges(hasUnsavedChanges); } + const unsavedPanelState = reactEmbeddableChanges.reduce( + (acc, { childId, unsavedChanges }) => { + acc[childId] = unsavedChanges; + return acc; + }, + {} as UnsavedPanelState + ); + // backup unsaved changes if configured to do so if (creationOptions?.useSessionStorageIntegration) { - backupUnsavedChanges.bind(this)( - dashboardChanges, - reactEmbeddableChanges, - controlGroupChanges - ); + backupUnsavedChanges.bind(this)(dashboardChanges, unsavedPanelState, controlGroupChanges); } }) ); @@ -209,36 +214,19 @@ export async function getDashboardUnsavedChanges( function backupUnsavedChanges( this: DashboardContainer, dashboardChanges: Partial, - reactEmbeddableChanges: Array<{ - childId: string; - unsavedChanges: object | undefined; - }>, + reactEmbeddableChanges: UnsavedPanelState, controlGroupChanges: PersistableControlGroupInput | undefined ) { const { dashboardBackup } = pluginServices.getServices(); - - // apply all unsaved state from react embeddables to the unsaved changes object. - let hasAnyReactEmbeddableUnsavedChanges = false; - const currentPanels = cloneDeep(dashboardChanges.panels ?? this.getInput().panels); - for (const { childId, unsavedChanges: childUnsavedChanges } of reactEmbeddableChanges) { - if (!childUnsavedChanges) continue; - const panelStateToBackup = { - ...currentPanels[childId], - ...(dashboardChanges.panels?.[childId] ?? {}), - explicitInput: { - ...currentPanels[childId]?.explicitInput, - ...(dashboardChanges.panels?.[childId]?.explicitInput ?? {}), - ...childUnsavedChanges, - }, - }; - hasAnyReactEmbeddableUnsavedChanges = true; - currentPanels[childId] = panelStateToBackup; - } const dashboardStateToBackup = omit(dashboardChanges, keysToOmitFromSessionStorage); - dashboardBackup.setState(this.getDashboardSavedObjectId(), { - ...dashboardStateToBackup, - panels: hasAnyReactEmbeddableUnsavedChanges ? currentPanels : dashboardChanges.panels, - controlGroupInput: controlGroupChanges, - }); + dashboardBackup.setState( + this.getDashboardSavedObjectId(), + { + ...dashboardStateToBackup, + panels: dashboardChanges.panels, + controlGroupInput: controlGroupChanges, + }, + reactEmbeddableChanges + ); } diff --git a/src/plugins/dashboard/public/dashboard_container/types.ts b/src/plugins/dashboard/public/dashboard_container/types.ts index 26f37d7f7d993..f3287494c7b66 100644 --- a/src/plugins/dashboard/public/dashboard_container/types.ts +++ b/src/plugins/dashboard/public/dashboard_container/types.ts @@ -14,6 +14,10 @@ import { SerializableRecord } from '@kbn/utility-types'; import type { DashboardContainerInput, DashboardOptions } from '../../common'; import { SavedDashboardPanel } from '../../common/content_management'; +export interface UnsavedPanelState { + [key: string]: object | undefined; +} + export type DashboardReduxState = ReduxEmbeddableState< DashboardContainerInput, DashboardContainerOutput, diff --git a/src/plugins/dashboard/public/services/dashboard_backup/dashboard_backup_service.ts b/src/plugins/dashboard/public/services/dashboard_backup/dashboard_backup_service.ts index fb5b2c12f05ee..5a121ef430400 100644 --- a/src/plugins/dashboard/public/services/dashboard_backup/dashboard_backup_service.ts +++ b/src/plugins/dashboard/public/services/dashboard_backup/dashboard_backup_service.ts @@ -20,11 +20,15 @@ import type { DashboardBackupServiceType } from './types'; import type { DashboardContainerInput } from '../../../common'; import { DashboardNotificationsService } from '../notifications/types'; import { backupServiceStrings } from '../../dashboard_container/_dashboard_container_strings'; +import { UnsavedPanelState } from '../../dashboard_container/types'; export const DASHBOARD_PANELS_UNSAVED_ID = 'unsavedDashboard'; -const DASHBOARD_PANELS_SESSION_KEY = 'dashboardStateManagerPanels'; +const DASHBOARD_PANELS_SESSION_KEY = 'dashboardPanels'; const DASHBOARD_VIEWMODE_LOCAL_KEY = 'dashboardViewMode'; +// this key is named `panels` for BWC reasons, but actually contains the entire dashboard state +const DASHBOARD_STATE_SESSION_KEY = 'dashboardStateManagerPanels'; + interface DashboardBackupRequiredServices { notifications: DashboardNotificationsService; spaces: DashboardSpacesService; @@ -75,11 +79,22 @@ class DashboardBackupService implements DashboardBackupServiceType { public clearState(id = DASHBOARD_PANELS_UNSAVED_ID) { try { - const sessionStorage = this.sessionStorage.get(DASHBOARD_PANELS_SESSION_KEY); - const sessionStorageForSpace = sessionStorage?.[this.activeSpaceId] || {}; - if (sessionStorageForSpace[id]) { - delete sessionStorageForSpace[id]; - this.sessionStorage.set(DASHBOARD_PANELS_SESSION_KEY, sessionStorage); + const dashboardStateStorage = + this.sessionStorage.get(DASHBOARD_STATE_SESSION_KEY)?.[this.activeSpaceId] ?? {}; + if (dashboardStateStorage[id]) { + delete dashboardStateStorage[id]; + this.sessionStorage.set(DASHBOARD_STATE_SESSION_KEY, { + [this.activeSpaceId]: dashboardStateStorage, + }); + } + + const panelsStorage = + this.sessionStorage.get(DASHBOARD_PANELS_SESSION_KEY)?.[this.activeSpaceId] ?? {}; + if (panelsStorage[id]) { + delete panelsStorage[id]; + this.sessionStorage.set(DASHBOARD_PANELS_SESSION_KEY, { + [this.activeSpaceId]: panelsStorage, + }); } } catch (e) { this.notifications.toasts.addDanger({ @@ -89,9 +104,15 @@ class DashboardBackupService implements DashboardBackupServiceType { } } - public getState(id = DASHBOARD_PANELS_UNSAVED_ID): Partial | undefined { + public getState(id = DASHBOARD_PANELS_UNSAVED_ID) { try { - return this.sessionStorage.get(DASHBOARD_PANELS_SESSION_KEY)?.[this.activeSpaceId]?.[id]; + const dashboardState = this.sessionStorage.get(DASHBOARD_STATE_SESSION_KEY)?.[ + this.activeSpaceId + ]?.[id] as Partial | undefined; + const panels = this.sessionStorage.get(DASHBOARD_PANELS_SESSION_KEY)?.[this.activeSpaceId]?.[ + id + ] as UnsavedPanelState | undefined; + return { dashboardState, panels }; } catch (e) { this.notifications.toasts.addDanger({ title: backupServiceStrings.getPanelsGetError(e.message), @@ -100,11 +121,19 @@ class DashboardBackupService implements DashboardBackupServiceType { } } - public setState(id = DASHBOARD_PANELS_UNSAVED_ID, newState: Partial) { + public setState( + id = DASHBOARD_PANELS_UNSAVED_ID, + newState: Partial, + unsavedPanels: UnsavedPanelState + ) { try { - const sessionStateStorage = this.sessionStorage.get(DASHBOARD_PANELS_SESSION_KEY) || {}; - set(sessionStateStorage, [this.activeSpaceId, id], newState); - this.sessionStorage.set(DASHBOARD_PANELS_SESSION_KEY, sessionStateStorage); + const dashboardStateStorage = this.sessionStorage.get(DASHBOARD_STATE_SESSION_KEY) ?? {}; + set(dashboardStateStorage, [this.activeSpaceId, id], newState); + this.sessionStorage.set(DASHBOARD_STATE_SESSION_KEY, dashboardStateStorage); + + const panelsStorage = this.sessionStorage.get(DASHBOARD_PANELS_SESSION_KEY) ?? {}; + set(panelsStorage, [this.activeSpaceId, id], unsavedPanels); + this.sessionStorage.set(DASHBOARD_PANELS_SESSION_KEY, panelsStorage); } catch (e) { this.notifications.toasts.addDanger({ title: backupServiceStrings.getPanelsSetError(e.message), @@ -116,18 +145,25 @@ class DashboardBackupService implements DashboardBackupServiceType { public getDashboardIdsWithUnsavedChanges() { try { const dashboardStatesInSpace = - this.sessionStorage.get(DASHBOARD_PANELS_SESSION_KEY)?.[this.activeSpaceId] || {}; - const dashboardsWithUnsavedChanges: string[] = []; - - Object.keys(dashboardStatesInSpace).map((dashboardId) => { - if ( - dashboardStatesInSpace[dashboardId].viewMode === ViewMode.EDIT && - Object.keys(dashboardStatesInSpace[dashboardId]).some( - (stateKey) => stateKey !== 'viewMode' + this.sessionStorage.get(DASHBOARD_STATE_SESSION_KEY)?.[this.activeSpaceId] ?? {}; + const panelStatesInSpace = + this.sessionStorage.get(DASHBOARD_PANELS_SESSION_KEY)?.[this.activeSpaceId] ?? {}; + + const dashboardsSet: Set = new Set(); + + [...Object.keys(panelStatesInSpace), ...Object.keys(dashboardStatesInSpace)].map( + (dashboardId) => { + if ( + dashboardStatesInSpace[dashboardId].viewMode === ViewMode.EDIT && + (Object.keys(dashboardStatesInSpace[dashboardId]).some( + (stateKey) => stateKey !== 'viewMode' + ) || + Object.keys(panelStatesInSpace?.[dashboardId]).length > 0) ) - ) - dashboardsWithUnsavedChanges.push(dashboardId); - }); + dashboardsSet.add(dashboardId); + } + ); + const dashboardsWithUnsavedChanges = [...dashboardsSet]; /** * Because we are storing these unsaved dashboard IDs in React component state, we only want things to be re-rendered diff --git a/src/plugins/dashboard/public/services/dashboard_backup/types.ts b/src/plugins/dashboard/public/services/dashboard_backup/types.ts index 70748085d3ee1..ee371a4463b56 100644 --- a/src/plugins/dashboard/public/services/dashboard_backup/types.ts +++ b/src/plugins/dashboard/public/services/dashboard_backup/types.ts @@ -7,12 +7,22 @@ */ import { ViewMode } from '@kbn/embeddable-plugin/public'; +import { UnsavedPanelState } from '../../dashboard_container/types'; import { SavedDashboardInput } from '../dashboard_content_management/types'; export interface DashboardBackupServiceType { clearState: (id?: string) => void; - getState: (id: string | undefined) => Partial | undefined; - setState: (id: string | undefined, newState: Partial) => void; + getState: (id: string | undefined) => + | { + dashboardState?: Partial; + panels?: UnsavedPanelState; + } + | undefined; + setState: ( + id: string | undefined, + dashboardState: Partial, + panels: UnsavedPanelState + ) => void; getViewMode: () => ViewMode; storeViewMode: (viewMode: ViewMode) => void; getDashboardIdsWithUnsavedChanges: () => string[]; diff --git a/src/plugins/discover/common/constants.ts b/src/plugins/discover/common/constants.ts index 8ac1280592ff6..5a203cba55878 100644 --- a/src/plugins/discover/common/constants.ts +++ b/src/plugins/discover/common/constants.ts @@ -15,6 +15,7 @@ export const ROWS_PER_PAGE_OPTIONS = [10, 25, 50, DEFAULT_ROWS_PER_PAGE, 250, 50 export enum VIEW_MODE { DOCUMENT_LEVEL = 'documents', AGGREGATED_LEVEL = 'aggregated', + PATTERN_LEVEL = 'patterns', } export const getDefaultRowsPerPage = (uiSettings: IUiSettingsClient): number => { diff --git a/src/plugins/discover/kibana.jsonc b/src/plugins/discover/kibana.jsonc index c9714054ee694..b35d9aa8dd489 100644 --- a/src/plugins/discover/kibana.jsonc +++ b/src/plugins/discover/kibana.jsonc @@ -39,7 +39,8 @@ "lens", "noDataPage", "globalSearch", - "observabilityAIAssistant" + "observabilityAIAssistant", + "aiops" ], "requiredBundles": ["kibanaUtils", "kibanaReact", "unifiedSearch", "savedObjects"], "extraPublicDirs": ["common"] diff --git a/src/plugins/discover/public/__mocks__/services.ts b/src/plugins/discover/public/__mocks__/services.ts index 2a0ffa9f7cb97..e4e2b71de8e74 100644 --- a/src/plugins/discover/public/__mocks__/services.ts +++ b/src/plugins/discover/public/__mocks__/services.ts @@ -156,6 +156,10 @@ export function createDiscoverServicesMock(): DiscoverServices { dataVisualizer: { FieldStatisticsTable: jest.fn(() => createElement('div')), }, + aiops: { + getPatternAnalysisAvailable: jest.fn().mockResolvedValue(jest.fn().mockResolvedValue(true)), + PatternAnalysisComponent: jest.fn(() => createElement('div')), + }, docLinks: docLinksServiceMock.createStartContract(), capabilities: { visualize: { diff --git a/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx b/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx index cc141ce3fd567..d141b89e453e3 100644 --- a/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx +++ b/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx @@ -87,6 +87,9 @@ export function DiscoverLayout({ stateContainer }: DiscoverLayoutProps) { ]); const isEsqlMode = useIsEsqlMode(); const viewMode: VIEW_MODE = useAppStateSelector((state) => { + if (state.viewMode === VIEW_MODE.DOCUMENT_LEVEL || state.viewMode === VIEW_MODE.PATTERN_LEVEL) { + return state.viewMode; + } if (uiSettings.get(SHOW_FIELD_STATISTICS) !== true || isEsqlMode) return VIEW_MODE.DOCUMENT_LEVEL; return state.viewMode ?? VIEW_MODE.DOCUMENT_LEVEL; diff --git a/src/plugins/discover/public/application/main/components/layout/discover_main_content.test.tsx b/src/plugins/discover/public/application/main/components/layout/discover_main_content.test.tsx index 2ea9825d3c5bd..343ceae3ed995 100644 --- a/src/plugins/discover/public/application/main/components/layout/discover_main_content.test.tsx +++ b/src/plugins/discover/public/application/main/components/layout/discover_main_content.test.tsx @@ -30,6 +30,7 @@ import { DocumentViewModeToggle } from '../../../../components/view_mode_toggle' import { searchSourceInstanceMock } from '@kbn/data-plugin/common/search/search_source/mocks'; import { DiscoverDocuments } from './discover_documents'; import { FieldStatisticsTab } from '../field_stats_table'; +import { PatternAnalysisTab } from '../pattern_analysis'; import { DiscoverMainProvider } from '../../state_management/discover_state_provider'; import { getDiscoverStateMock } from '../../../../__mocks__/discover_state.mock'; import { PanelsToggle } from '../../../../components/panels_toggle'; @@ -189,13 +190,22 @@ describe('Discover main content component', () => { it('should show DiscoverDocuments when VIEW_MODE is DOCUMENT_LEVEL', async () => { const component = await mountComponent(); expect(component.find(DiscoverDocuments).exists()).toBe(true); + expect(component.find(PatternAnalysisTab).exists()).toBe(false); expect(component.find(FieldStatisticsTab).exists()).toBe(false); }); - it('should show FieldStatisticsTableMemoized when VIEW_MODE is not DOCUMENT_LEVEL', async () => { + it('should show FieldStatisticsTab when VIEW_MODE is AGGREGATED_LEVEL', async () => { const component = await mountComponent({ viewMode: VIEW_MODE.AGGREGATED_LEVEL }); expect(component.find(DiscoverDocuments).exists()).toBe(false); + expect(component.find(PatternAnalysisTab).exists()).toBe(false); expect(component.find(FieldStatisticsTab).exists()).toBe(true); }); + + it('should show PatternAnalysisTab when VIEW_MODE is PATTERN_LEVEL', async () => { + const component = await mountComponent({ viewMode: VIEW_MODE.PATTERN_LEVEL }); + expect(component.find(DiscoverDocuments).exists()).toBe(false); + expect(component.find(PatternAnalysisTab).exists()).toBe(true); + expect(component.find(FieldStatisticsTab).exists()).toBe(false); + }); }); }); diff --git a/src/plugins/discover/public/application/main/components/layout/discover_main_content.tsx b/src/plugins/discover/public/application/main/components/layout/discover_main_content.tsx index 23e4001a39459..7c44ed1deff83 100644 --- a/src/plugins/discover/public/application/main/components/layout/discover_main_content.tsx +++ b/src/plugins/discover/public/application/main/components/layout/discover_main_content.tsx @@ -22,6 +22,8 @@ import { DiscoverDocuments } from './discover_documents'; import { DOCUMENTS_VIEW_CLICK, FIELD_STATISTICS_VIEW_CLICK } from '../field_stats_table/constants'; import { useAppStateSelector } from '../../state_management/discover_app_state_container'; import type { PanelsToggleProps } from '../../../../components/panels_toggle'; +import { PatternAnalysisTab } from '../pattern_analysis/pattern_analysis_tab'; +import { PATTERN_ANALYSIS_VIEW_CLICK } from '../pattern_analysis/constants'; import { useIsEsqlMode } from '../../hooks/use_is_esql_mode'; const DROP_PROPS = { @@ -60,9 +62,8 @@ export const DiscoverMainContent = ({ panelsToggle, isChartAvailable, }: DiscoverMainContentProps) => { - const { trackUiMetric, dataVisualizer: dataVisualizerService } = useDiscoverServices(); + const { trackUiMetric } = useDiscoverServices(); const isEsqlMode = useIsEsqlMode(); - const shouldShowViewModeToggle = dataVisualizerService !== undefined; const setDiscoverViewMode = useCallback( (mode: VIEW_MODE) => { @@ -71,6 +72,8 @@ export const DiscoverMainContent = ({ if (trackUiMetric) { if (mode === VIEW_MODE.AGGREGATED_LEVEL) { trackUiMetric(METRIC_TYPE.CLICK, FIELD_STATISTICS_VIEW_CLICK); + } else if (mode === VIEW_MODE.PATTERN_LEVEL) { + trackUiMetric(METRIC_TYPE.CLICK, PATTERN_ANALYSIS_VIEW_CLICK); } else { trackUiMetric(METRIC_TYPE.CLICK, DOCUMENTS_VIEW_CLICK); } @@ -81,31 +84,36 @@ export const DiscoverMainContent = ({ const isDropAllowed = Boolean(onDropFieldToTable); - const viewModeToggle = useMemo(() => { - return shouldShowViewModeToggle ? ( - - ) : ( - - ); - }, [ - shouldShowViewModeToggle, - viewMode, - isEsqlMode, - stateContainer, - setDiscoverViewMode, - panelsToggle, - isChartAvailable, - ]); + const renderViewModeToggle = useCallback( + (patternCount?: number) => { + return ( + + ); + }, + [ + viewMode, + isEsqlMode, + stateContainer, + setDiscoverViewMode, + dataView, + panelsToggle, + isChartAvailable, + ] + ); + + const viewModeToggle = useMemo(() => renderViewModeToggle(), [renderViewModeToggle]); const showChart = useAppStateSelector((state) => !state.hideChart); @@ -133,7 +141,8 @@ export const DiscoverMainContent = ({ stateContainer={stateContainer} onFieldEdited={!isEsqlMode ? onFieldEdited : undefined} /> - ) : ( + ) : null} + {viewMode === VIEW_MODE.AGGREGATED_LEVEL ? ( <> {viewModeToggle} - )} + ) : null} + {viewMode === VIEW_MODE.PATTERN_LEVEL ? ( + setDiscoverViewMode(VIEW_MODE.DOCUMENT_LEVEL)} + trackUiMetric={trackUiMetric} + renderViewModeToggle={renderViewModeToggle} + /> + ) : null} diff --git a/src/plugins/discover/public/application/main/components/pattern_analysis/constants.ts b/src/plugins/discover/public/application/main/components/pattern_analysis/constants.ts new file mode 100644 index 0000000000000..8441a308965e7 --- /dev/null +++ b/src/plugins/discover/public/application/main/components/pattern_analysis/constants.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. + */ + +/** Telemetry related to field statistics table **/ +export const PATTERN_ANALYSIS_LOADED = 'pattern_analysis_loaded'; +export const PATTERN_ANALYSIS_VIEW_CLICK = 'pattern_analysis_view_click'; diff --git a/packages/solution-nav/es/jest.config.js b/src/plugins/discover/public/application/main/components/pattern_analysis/index.ts similarity index 73% rename from packages/solution-nav/es/jest.config.js rename to src/plugins/discover/public/application/main/components/pattern_analysis/index.ts index 5c651f7bb9bbe..8741f1040edb4 100644 --- a/packages/solution-nav/es/jest.config.js +++ b/src/plugins/discover/public/application/main/components/pattern_analysis/index.ts @@ -6,8 +6,5 @@ * Side Public License, v 1. */ -module.exports = { - preset: '@kbn/test', - rootDir: '../../..', - roots: ['/packages/solution-nav/es'], -}; +export { PatternAnalysisTable } from './pattern_analysis_table'; +export { PatternAnalysisTab } from './pattern_analysis_tab'; diff --git a/src/plugins/discover/public/application/main/components/pattern_analysis/pattern_analysis_tab.tsx b/src/plugins/discover/public/application/main/components/pattern_analysis/pattern_analysis_tab.tsx new file mode 100644 index 0000000000000..db02134e0169f --- /dev/null +++ b/src/plugins/discover/public/application/main/components/pattern_analysis/pattern_analysis_tab.tsx @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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, { memo, type FC } from 'react'; +import { useQuerySubscriber } from '@kbn/unified-field-list/src/hooks/use_query_subscriber'; +import { useSavedSearch } from '../../state_management/discover_state_provider'; +import { PatternAnalysisTable, type PatternAnalysisTableProps } from './pattern_analysis_table'; +import { useDiscoverServices } from '../../../../hooks/use_discover_services'; + +export const PatternAnalysisTab: FC> = memo( + (props) => { + const services = useDiscoverServices(); + const querySubscriberResult = useQuerySubscriber({ + data: services.data, + }); + const savedSearch = useSavedSearch(); + + return ( + + ); + } +); diff --git a/src/plugins/discover/public/application/main/components/pattern_analysis/pattern_analysis_table.tsx b/src/plugins/discover/public/application/main/components/pattern_analysis/pattern_analysis_table.tsx new file mode 100644 index 0000000000000..ccbb2a6e72b8c --- /dev/null +++ b/src/plugins/discover/public/application/main/components/pattern_analysis/pattern_analysis_table.tsx @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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, { useEffect, useState, useMemo } from 'react'; +import { METRIC_TYPE, UiCounterMetricType } from '@kbn/analytics'; +import { type EmbeddablePatternAnalysisInput } from '@kbn/aiops-log-pattern-analysis/embeddable'; +import { pick } from 'lodash'; +import type { LogCategorizationEmbeddableProps } from '@kbn/aiops-plugin/public/components/log_categorization/log_categorization_for_embeddable/log_categorization_for_embeddable'; +import { useDiscoverServices } from '../../../../hooks/use_discover_services'; +import type { DiscoverStateContainer } from '../../state_management/discover_state'; +import { PATTERN_ANALYSIS_LOADED } from './constants'; + +export type PatternAnalysisTableProps = EmbeddablePatternAnalysisInput & { + stateContainer?: DiscoverStateContainer; + trackUiMetric?: (metricType: UiCounterMetricType, eventName: string | string[]) => void; + renderViewModeToggle: (patternCount?: number) => React.ReactElement; +}; + +export const PatternAnalysisTable = (props: PatternAnalysisTableProps) => { + const [lastReloadRequestTime, setLastReloadRequestTime] = useState(undefined); + + const services = useDiscoverServices(); + const aiopsService = services.aiops; + const { trackUiMetric, stateContainer } = props; + + useEffect(() => { + const refetch = stateContainer?.dataState.refetch$.subscribe(() => { + setLastReloadRequestTime(Date.now()); + }); + + return () => { + refetch?.unsubscribe(); + }; + }, [stateContainer]); + + useEffect(() => { + // Track should only be called once when component is loaded + if (aiopsService) { + trackUiMetric?.(METRIC_TYPE.LOADED, PATTERN_ANALYSIS_LOADED); + } + }, [aiopsService, trackUiMetric]); + + const patternAnalysisComponentProps: LogCategorizationEmbeddableProps = useMemo( + () => ({ + input: Object.assign( + {}, + pick(props, ['dataView', 'savedSearch', 'query', 'filters', 'switchToDocumentView']), + { lastReloadRequestTime } + ), + renderViewModeToggle: props.renderViewModeToggle, + }), + [lastReloadRequestTime, props] + ); + + if (!aiopsService) { + return null; + } + + return ( + + ); +}; diff --git a/src/plugins/discover/public/application/main/hooks/use_esql_mode.test.tsx b/src/plugins/discover/public/application/main/hooks/use_esql_mode.test.tsx index 5ae16f0429288..b24bcd3eb42d5 100644 --- a/src/plugins/discover/public/application/main/hooks/use_esql_mode.test.tsx +++ b/src/plugins/discover/public/application/main/hooks/use_esql_mode.test.tsx @@ -114,6 +114,18 @@ describe('useEsqlMode', () => { viewMode: undefined, }); }); + + test('should change viewMode to undefined (default) if it was PATTERN_LEVEL', async () => { + const { replaceUrlState } = renderHookWithContext(false, { + viewMode: VIEW_MODE.PATTERN_LEVEL, + }); + + await waitFor(() => expect(replaceUrlState).toHaveBeenCalledTimes(1)); + expect(replaceUrlState).toHaveBeenCalledWith({ + viewMode: undefined, + }); + }); + test('changing an ES|QL query with different result columns should change state when loading and finished', async () => { const { replaceUrlState, stateContainer } = renderHookWithContext(false); const documents$ = stateContainer.dataState.data$.documents$; diff --git a/src/plugins/discover/public/application/main/state_management/utils/get_state_defaults.test.ts b/src/plugins/discover/public/application/main/state_management/utils/get_state_defaults.test.ts index ac85a24f91f34..28c562d3e7051 100644 --- a/src/plugins/discover/public/application/main/state_management/utils/get_state_defaults.test.ts +++ b/src/plugins/discover/public/application/main/state_management/utils/get_state_defaults.test.ts @@ -98,14 +98,23 @@ describe('getStateDefaults', () => { }); expect(actualForUndefinedViewMode.viewMode).toBeUndefined(); - const actualForEsqlWithInvalidViewMode = getStateDefaults({ + const actualForEsqlWithInvalidAggLevelViewMode = getStateDefaults({ services: discoverServiceMock, savedSearch: { ...savedSearchMockWithESQL, viewMode: VIEW_MODE.AGGREGATED_LEVEL, }, }); - expect(actualForEsqlWithInvalidViewMode.viewMode).toBe(VIEW_MODE.DOCUMENT_LEVEL); + expect(actualForEsqlWithInvalidAggLevelViewMode.viewMode).toBe(VIEW_MODE.DOCUMENT_LEVEL); + + const actualForEsqlWithInvalidPatternLevelViewMode = getStateDefaults({ + services: discoverServiceMock, + savedSearch: { + ...savedSearchMockWithESQL, + viewMode: VIEW_MODE.PATTERN_LEVEL, + }, + }); + expect(actualForEsqlWithInvalidPatternLevelViewMode.viewMode).toBe(VIEW_MODE.DOCUMENT_LEVEL); const actualForEsqlWithValidViewMode = getStateDefaults({ services: discoverServiceMock, @@ -117,15 +126,29 @@ describe('getStateDefaults', () => { expect(actualForEsqlWithValidViewMode.viewMode).toBe(VIEW_MODE.DOCUMENT_LEVEL); expect(actualForEsqlWithValidViewMode.dataSource).toEqual(createEsqlDataSource()); - const actualForWithValidViewMode = getStateDefaults({ + const actualForWithValidAggLevelViewMode = getStateDefaults({ services: discoverServiceMock, savedSearch: { ...savedSearchMock, viewMode: VIEW_MODE.AGGREGATED_LEVEL, }, }); - expect(actualForWithValidViewMode.viewMode).toBe(VIEW_MODE.AGGREGATED_LEVEL); - expect(actualForWithValidViewMode.dataSource).toEqual( + expect(actualForWithValidAggLevelViewMode.viewMode).toBe(VIEW_MODE.AGGREGATED_LEVEL); + expect(actualForWithValidAggLevelViewMode.dataSource).toEqual( + createDataViewDataSource({ + dataViewId: savedSearchMock.searchSource.getField('index')?.id!, + }) + ); + + const actualForWithValidPatternLevelViewMode = getStateDefaults({ + services: discoverServiceMock, + savedSearch: { + ...savedSearchMock, + viewMode: VIEW_MODE.PATTERN_LEVEL, + }, + }); + expect(actualForWithValidPatternLevelViewMode.viewMode).toBe(VIEW_MODE.PATTERN_LEVEL); + expect(actualForWithValidPatternLevelViewMode.dataSource).toEqual( createDataViewDataSource({ dataViewId: savedSearchMock.searchSource.getField('index')?.id!, }) diff --git a/src/plugins/discover/public/application/main/utils/get_valid_view_mode.test.ts b/src/plugins/discover/public/application/main/utils/get_valid_view_mode.test.ts index 51530926defbf..ff2d4250b3da8 100644 --- a/src/plugins/discover/public/application/main/utils/get_valid_view_mode.test.ts +++ b/src/plugins/discover/public/application/main/utils/get_valid_view_mode.test.ts @@ -31,6 +31,13 @@ describe('getValidViewMode', () => { isEsqlMode: false, }) ).toBe(VIEW_MODE.AGGREGATED_LEVEL); + + expect( + getValidViewMode({ + viewMode: VIEW_MODE.PATTERN_LEVEL, + isEsqlMode: false, + }) + ).toBe(VIEW_MODE.PATTERN_LEVEL); }); test('should work correctly for ES|QL mode', () => { @@ -54,5 +61,12 @@ describe('getValidViewMode', () => { isEsqlMode: true, }) ).toBe(VIEW_MODE.DOCUMENT_LEVEL); + + expect( + getValidViewMode({ + viewMode: VIEW_MODE.PATTERN_LEVEL, + isEsqlMode: true, + }) + ).toBe(VIEW_MODE.DOCUMENT_LEVEL); }); }); diff --git a/src/plugins/discover/public/application/main/utils/get_valid_view_mode.ts b/src/plugins/discover/public/application/main/utils/get_valid_view_mode.ts index eab9677f083b2..03c3500b7ab2d 100644 --- a/src/plugins/discover/public/application/main/utils/get_valid_view_mode.ts +++ b/src/plugins/discover/public/application/main/utils/get_valid_view_mode.ts @@ -20,8 +20,11 @@ export const getValidViewMode = ({ viewMode?: VIEW_MODE; isEsqlMode: boolean; }): VIEW_MODE | undefined => { - if (viewMode === VIEW_MODE.AGGREGATED_LEVEL && isEsqlMode) { - // only this mode is supported for ES|QL languages + if ( + (viewMode === VIEW_MODE.PATTERN_LEVEL || viewMode === VIEW_MODE.AGGREGATED_LEVEL) && + isEsqlMode + ) { + // only this mode is supported for text-based languages return VIEW_MODE.DOCUMENT_LEVEL; } diff --git a/src/plugins/discover/public/build_services.ts b/src/plugins/discover/public/build_services.ts index 91242f3b1cb93..e3524dcdf115c 100644 --- a/src/plugins/discover/public/build_services.ts +++ b/src/plugins/discover/public/build_services.ts @@ -57,6 +57,7 @@ import type { ContentClient } from '@kbn/content-management-plugin/public'; import type { ObservabilityAIAssistantPublicStart } from '@kbn/observability-ai-assistant-plugin/public'; 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 { DiscoverStartPlugins } from './plugin'; import { DiscoverContextAppLocator } from './application/context/services/locator'; @@ -77,6 +78,7 @@ export interface UrlTracker { } export interface DiscoverServices { + aiops?: AiopsPluginStart; application: ApplicationStart; addBasePath: (path: string) => string; analytics: AnalyticsServiceStart; @@ -157,6 +159,7 @@ export const buildServices = memoize( const storage = new Storage(localStorage); return { + aiops: plugins.aiops, application: core.application, addBasePath: core.http.basePath.prepend, analytics: core.analytics, diff --git a/src/plugins/discover/public/components/doc_table/components/table_row/__snapshots__/table_cell.test.tsx.snap b/src/plugins/discover/public/components/doc_table/components/table_row/__snapshots__/table_cell.test.tsx.snap index 555be566a5082..a6449fd265492 100644 --- a/src/plugins/discover/public/components/doc_table/components/table_row/__snapshots__/table_cell.test.tsx.snap +++ b/src/plugins/discover/public/components/doc_table/components/table_row/__snapshots__/table_cell.test.tsx.snap @@ -40,11 +40,13 @@ exports[`Doc table cell component renders a cell with filter buttons if it is fi isVisible={false} onBlur={[Function]} onFocus={[Function]} + onKeyDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} > @@ -124,6 +126,7 @@ exports[`Doc table cell component renders a cell with filter buttons if it is fi /> @@ -164,11 +167,13 @@ exports[`Doc table cell component renders a cell with filter buttons if it is fi isVisible={false} onBlur={[Function]} onFocus={[Function]} + onKeyDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} > @@ -248,6 +253,7 @@ exports[`Doc table cell component renders a cell with filter buttons if it is fi /> diff --git a/src/plugins/discover/public/components/view_mode_toggle/view_mode_toggle.test.tsx b/src/plugins/discover/public/components/view_mode_toggle/view_mode_toggle.test.tsx index afc59b6e7d0c6..4d266af5e7949 100644 --- a/src/plugins/discover/public/components/view_mode_toggle/view_mode_toggle.test.tsx +++ b/src/plugins/discover/public/components/view_mode_toggle/view_mode_toggle.test.tsx @@ -12,84 +12,153 @@ import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { mountWithIntl } from '@kbn/test-jest-helpers'; import React from 'react'; import { findTestSubject } from '@elastic/eui/lib/test'; +import type { DataView } from '@kbn/data-views-plugin/common'; import { DocumentViewModeToggle } from './view_mode_toggle'; import { BehaviorSubject } from 'rxjs'; import { getDiscoverStateMock } from '../../__mocks__/discover_state.mock'; import { DataTotalHits$ } from '../../application/main/state_management/discover_data_state_container'; import { FetchStatus } from '../../application/types'; +import { ES_FIELD_TYPES } from '@kbn/field-types'; import { discoverServiceMock } from '../../__mocks__/services'; +import { act } from 'react-dom/test-utils'; describe('Document view mode toggle component', () => { - const mountComponent = ({ + const mountComponent = async ({ showFieldStatistics = true, viewMode = VIEW_MODE.DOCUMENT_LEVEL, isEsqlMode = false, setDiscoverViewMode = jest.fn(), + useDataViewWithTextFields = true, } = {}) => { const services = { ...discoverServiceMock, uiSettings: { get: () => showFieldStatistics, }, + aiops: { + getPatternAnalysisAvailable: jest + .fn() + .mockResolvedValue(jest.fn().mockResolvedValue(useDataViewWithTextFields)), + }, }; + const dataViewWithTextFields = { + fields: [ + { + name: 'field1', + esTypes: [ES_FIELD_TYPES.TEXT], + }, + ], + } as unknown as DataView; + + const dataViewWithoutTextFields = { + fields: [ + { + name: 'field1', + esTypes: [ES_FIELD_TYPES.FLOAT], + }, + ], + } as unknown as DataView; + const stateContainer = getDiscoverStateMock({ isTimeBased: true }); stateContainer.dataState.data$.totalHits$ = new BehaviorSubject({ fetchStatus: FetchStatus.COMPLETE, result: 10, }) as DataTotalHits$; - return mountWithIntl( + const component = mountWithIntl( ); + + await act(async () => { + component.update(); + }); + component!.update(); + return component!; }; - it('should render if SHOW_FIELD_STATISTICS is true', () => { - const component = mountComponent(); + it('should render if SHOW_FIELD_STATISTICS is true', async () => { + const component = await mountComponent(); expect(findTestSubject(component, 'dscViewModeToggle').exists()).toBe(true); expect(findTestSubject(component, 'discoverQueryTotalHits').exists()).toBe(true); + + expect(findTestSubject(component, 'dscViewModeDocumentButton').exists()).toBe(true); + expect(findTestSubject(component, 'dscViewModePatternAnalysisButton').exists()).toBe(true); + expect(findTestSubject(component, 'dscViewModeFieldStatsButton').exists()).toBe(true); }); - it('should not render if SHOW_FIELD_STATISTICS is false', () => { - const component = mountComponent({ showFieldStatistics: false }); - expect(findTestSubject(component, 'dscViewModeToggle').exists()).toBe(false); + it('should not render if SHOW_FIELD_STATISTICS is false', async () => { + const component = await mountComponent({ showFieldStatistics: false }); + expect(findTestSubject(component, 'dscViewModeToggle').exists()).toBe(true); expect(findTestSubject(component, 'discoverQueryTotalHits').exists()).toBe(true); + + expect(findTestSubject(component, 'dscViewModeDocumentButton').exists()).toBe(true); + expect(findTestSubject(component, 'dscViewModePatternAnalysisButton').exists()).toBe(true); + expect(findTestSubject(component, 'dscViewModeFieldStatsButton').exists()).toBe(false); }); - it('should not render if ES|QL', () => { - const component = mountComponent({ isEsqlMode: true }); + it('should not render if ES|QL', async () => { + const component = await mountComponent({ isEsqlMode: true }); expect(findTestSubject(component, 'dscViewModeToggle').exists()).toBe(false); expect(findTestSubject(component, 'discoverQueryTotalHits').exists()).toBe(true); + + expect(findTestSubject(component, 'dscViewModeDocumentButton').exists()).toBe(false); + expect(findTestSubject(component, 'dscViewModePatternAnalysisButton').exists()).toBe(false); + expect(findTestSubject(component, 'dscViewModeFieldStatsButton').exists()).toBe(false); }); - it('should set the view mode to VIEW_MODE.DOCUMENT_LEVEL when dscViewModeDocumentButton is clicked', () => { + it('should set the view mode to VIEW_MODE.DOCUMENT_LEVEL when dscViewModeDocumentButton is clicked', async () => { const setDiscoverViewMode = jest.fn(); - const component = mountComponent({ setDiscoverViewMode }); + const component = await mountComponent({ setDiscoverViewMode }); component.find('[data-test-subj="dscViewModeDocumentButton"]').at(0).simulate('click'); expect(setDiscoverViewMode).toHaveBeenCalledWith(VIEW_MODE.DOCUMENT_LEVEL); }); - it('should set the view mode to VIEW_MODE.AGGREGATED_LEVEL when dscViewModeFieldStatsButton is clicked', () => { + it('should set the view mode to VIEW_MODE.PATTERN_LEVEL when dscViewModePatternAnalysisButton is clicked', async () => { const setDiscoverViewMode = jest.fn(); - const component = mountComponent({ setDiscoverViewMode }); + const component = await mountComponent({ setDiscoverViewMode }); + component.find('[data-test-subj="dscViewModePatternAnalysisButton"]').at(0).simulate('click'); + expect(setDiscoverViewMode).toHaveBeenCalledWith(VIEW_MODE.PATTERN_LEVEL); + }); + + it('should set the view mode to VIEW_MODE.AGGREGATED_LEVEL when dscViewModeFieldStatsButton is clicked', async () => { + const setDiscoverViewMode = jest.fn(); + const component = await mountComponent({ setDiscoverViewMode }); component.find('[data-test-subj="dscViewModeFieldStatsButton"]').at(0).simulate('click'); expect(setDiscoverViewMode).toHaveBeenCalledWith(VIEW_MODE.AGGREGATED_LEVEL); }); - it('should select the Documents tab if viewMode is VIEW_MODE.DOCUMENT_LEVEL', () => { - const component = mountComponent(); + it('should select the Documents tab if viewMode is VIEW_MODE.DOCUMENT_LEVEL', async () => { + const component = await mountComponent(); expect(component.find(EuiTab).at(0).prop('isSelected')).toBe(true); }); - it('should select the Field statistics tab if viewMode is VIEW_MODE.AGGREGATED_LEVEL', () => { - const component = mountComponent({ viewMode: VIEW_MODE.AGGREGATED_LEVEL }); + it('should select the Pattern Analysis tab if viewMode is VIEW_MODE.PATTERN_LEVEL', async () => { + const component = await mountComponent({ viewMode: VIEW_MODE.PATTERN_LEVEL }); expect(component.find(EuiTab).at(1).prop('isSelected')).toBe(true); }); + + it('should select the Field statistics tab if viewMode is VIEW_MODE.AGGREGATED_LEVEL', async () => { + const component = await mountComponent({ viewMode: VIEW_MODE.AGGREGATED_LEVEL }); + expect(component.find(EuiTab).at(2).prop('isSelected')).toBe(true); + }); + + it('should switch to document and hide pattern tab when there are no text fields', async () => { + const setDiscoverViewMode = jest.fn(); + const component = await mountComponent({ + viewMode: VIEW_MODE.PATTERN_LEVEL, + useDataViewWithTextFields: false, + setDiscoverViewMode, + }); + expect(setDiscoverViewMode).toHaveBeenCalledWith(VIEW_MODE.DOCUMENT_LEVEL); + expect(component.find(EuiTab).length).toBe(2); + }); }); diff --git a/src/plugins/discover/public/components/view_mode_toggle/view_mode_toggle.tsx b/src/plugins/discover/public/components/view_mode_toggle/view_mode_toggle.tsx index b9b036e266b4e..11351893b6a26 100644 --- a/src/plugins/discover/public/components/view_mode_toggle/view_mode_toggle.tsx +++ b/src/plugins/discover/public/components/view_mode_toggle/view_mode_toggle.tsx @@ -6,14 +6,16 @@ * Side Public License, v 1. */ -import React, { useMemo, ReactElement } from 'react'; +import React, { useMemo, useEffect, useState, type ReactElement, useCallback } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiTab, EuiTabs, useEuiTheme } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { css } from '@emotion/react'; import { isLegacyTableEnabled, SHOW_FIELD_STATISTICS } from '@kbn/discover-utils'; +import type { DataView } from '@kbn/data-views-plugin/common'; +import useMountedState from 'react-use/lib/useMountedState'; import { VIEW_MODE } from '../../../common/constants'; import { useDiscoverServices } from '../../hooks/use_discover_services'; -import { DiscoverStateContainer } from '../../application/main/state_management/discover_state'; +import type { DiscoverStateContainer } from '../../application/main/state_management/discover_state'; import { HitsCounter, HitsCounterMode } from '../hits_counter'; export const DocumentViewModeToggle = ({ @@ -22,20 +24,70 @@ export const DocumentViewModeToggle = ({ prepend, stateContainer, setDiscoverViewMode, + patternCount, + dataView, }: { viewMode: VIEW_MODE; isEsqlMode: boolean; prepend?: ReactElement; stateContainer: DiscoverStateContainer; setDiscoverViewMode: (viewMode: VIEW_MODE) => void; + patternCount?: number; + dataView: DataView; }) => { const { euiTheme } = useEuiTheme(); - const { uiSettings, dataVisualizer: dataVisualizerService } = useDiscoverServices(); + const { + uiSettings, + dataVisualizer: dataVisualizerService, + aiops: aiopsService, + } = useDiscoverServices(); const isLegacy = useMemo( () => isLegacyTableEnabled({ uiSettings, isEsqlMode }), [uiSettings, isEsqlMode] ); - const includesNormalTabsStyle = viewMode === VIEW_MODE.AGGREGATED_LEVEL || isLegacy; + const [showPatternAnalysisTab, setShowPatternAnalysisTab] = useState(null); + const showFieldStatisticsTab = useMemo( + () => uiSettings.get(SHOW_FIELD_STATISTICS) && dataVisualizerService !== undefined, + [dataVisualizerService, uiSettings] + ); + const isMounted = useMountedState(); + + const setShowPatternAnalysisTabWrapper = useCallback( + (value: boolean) => { + if (isMounted()) { + setShowPatternAnalysisTab(value); + } + }, + [isMounted] + ); + + useEffect( + function checkForPatternAnalysis() { + if (!aiopsService) { + setShowPatternAnalysisTab(false); + return; + } + aiopsService + .getPatternAnalysisAvailable() + .then((patternAnalysisAvailable) => { + patternAnalysisAvailable(dataView) + .then(setShowPatternAnalysisTabWrapper) + .catch(() => setShowPatternAnalysisTabWrapper(false)); + }) + .catch(() => setShowPatternAnalysisTabWrapper(false)); + }, + [aiopsService, dataView, setShowPatternAnalysisTabWrapper] + ); + + useEffect(() => { + if (showPatternAnalysisTab === false && viewMode === VIEW_MODE.PATTERN_LEVEL) { + // switch to document view if no text fields are available + setDiscoverViewMode(VIEW_MODE.DOCUMENT_LEVEL); + } + }, [showPatternAnalysisTab, viewMode, setDiscoverViewMode]); + + const includesNormalTabsStyle = + viewMode === VIEW_MODE.AGGREGATED_LEVEL || viewMode === VIEW_MODE.PATTERN_LEVEL || isLegacy; const containerPadding = includesNormalTabsStyle ? euiTheme.size.s : 0; const containerCss = css` @@ -48,9 +100,6 @@ export const DocumentViewModeToggle = ({ } `; - const showViewModeToggle = - (uiSettings.get(SHOW_FIELD_STATISTICS) && dataVisualizerService !== undefined) ?? false; - return ( )} - {isEsqlMode || !showViewModeToggle ? ( + {isEsqlMode || (showFieldStatisticsTab === false && showPatternAnalysisTab === false) ? ( ) : ( @@ -84,16 +133,33 @@ export const DocumentViewModeToggle = ({ - setDiscoverViewMode(VIEW_MODE.AGGREGATED_LEVEL)} - data-test-subj="dscViewModeFieldStatsButton" - > - - + + {showPatternAnalysisTab ? ( + setDiscoverViewMode(VIEW_MODE.PATTERN_LEVEL)} + data-test-subj="dscViewModePatternAnalysisButton" + > + + + ) : null} + + {showFieldStatisticsTab ? ( + setDiscoverViewMode(VIEW_MODE.AGGREGATED_LEVEL)} + data-test-subj="dscViewModeFieldStatsButton" + > + + + ) : null} )} diff --git a/src/plugins/discover/public/plugin.tsx b/src/plugins/discover/public/plugin.tsx index a5ab80cbf4857..2eb34b20345e4 100644 --- a/src/plugins/discover/public/plugin.tsx +++ b/src/plugins/discover/public/plugin.tsx @@ -51,6 +51,7 @@ import type { ObservabilityAIAssistantPublicSetup, ObservabilityAIAssistantPublicStart, } 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 { PLUGIN_ID } from '../common'; import { registerFeature } from './register_feature'; @@ -179,6 +180,7 @@ export interface DiscoverSetupPlugins { * @internal */ export interface DiscoverStartPlugins { + aiops?: AiopsPluginStart; dataViews: DataViewsServicePublic; dataViewEditor: DataViewEditorStart; dataVisualizer?: DataVisualizerPluginStart; diff --git a/src/plugins/discover/tsconfig.json b/src/plugins/discover/tsconfig.json index bf4c06f1c5dbe..970f8753a8cdc 100644 --- a/src/plugins/discover/tsconfig.json +++ b/src/plugins/discover/tsconfig.json @@ -84,12 +84,14 @@ "@kbn/shared-ux-markdown", "@kbn/data-view-utils", "@kbn/presentation-publishing", + "@kbn/aiops-log-pattern-analysis", + "@kbn/field-types", "@kbn/elastic-agent-utils", "@kbn/custom-icons", "@kbn/observability-ai-assistant-plugin", + "@kbn/aiops-plugin", "@kbn/data-visualizer-plugin", "@kbn/search-types", - "@kbn/custom-icons", "@kbn/observability-ai-assistant-plugin" ], "exclude": ["target/**/*"] diff --git a/src/plugins/embeddable/README.md b/src/plugins/embeddable/README.md index d4c9a5ca23193..0612226664da4 100644 --- a/src/plugins/embeddable/README.md +++ b/src/plugins/embeddable/README.md @@ -1,21 +1,55 @@ Embeddables are React components that manage their own state, can be serialized and deserialized, and return an API that can be used to interact with them imperatively. -#### Guiding principles -* **Coupled to React:** Kibana is a React application, and the minimum unit of sharing is the React component. Embeddables enforce this by requiring a React component during registration. -* **Composition over inheritence:** Rather than an inheritance-based system with classes, imperative APIs are plain old typescript objects that implement any number of shared interfaces. Interfaces are enforced via type guards and are shared via Packages. -* **Internal state management:** Each embeddable manages its own state. This is because the embeddable system allows a page to render a registry of embeddable types that can change over time. This makes it untenable for a single page to manage state for every type of embeddable. The page is only responsible for persisting and providing the last persisted state to the embeddable on startup. +### Guiding principles -#### Best practices -* **Do not use Embeddables to share Components between plugins: ** Only create an embeddable if your Component is rendered on a page that persists embeddable state and renders multiple embeddable types. For example, create an embeddable to render your Component on a Dashboard. Otherwise, use a vanilla React Component to share Components between plugins. -* **Do not use Embeddables to avoid circular plugin dependencies: ** Break your Component into a Package or another plugin to avoid circular plugin dependencies. -* **Minimal API surface area: ** Embeddable APIs are accessable to all Kibana systems and all embeddable siblings and parents. Functions and state that are internal to an embeddable including any child components should not be added to the API. Consider passing internal state to child as props or react context. +#### Coupled to React +Kibana is a React application, and the minimum unit of sharing is the React component. Embeddables enforce this by requiring a React component during registration. + +#### Composition over inheritence +Rather than an inheritance-based system with classes, imperative APIs are plain old typescript objects that implement any number of shared interfaces. Interfaces are enforced via type guards and are shared via Packages. + +#### Internal state management +Each embeddable manages its own state. This is because the embeddable system allows a page to render a registry of embeddable types that can change over time. This makes it untenable for a single page to manage state for every type of embeddable. The page is only responsible for persisting and providing the last persisted state to the embeddable on startup. + +### Key concepts + +#### Publishing package +An embeddable API is a plain old typescript object that implements any number of shared interfaces. A shared interface is defined by a publishing package. A publishing package also provides a type guard that is used to check if a given object fulfills the interface. + +For example, the [has_edit_capabilites](https://github.com/elastic/kibana/tree/main/packages/presentation/presentation_publishing/interfaces/has_edit_capabilities.ts) publishing package defines the `HasEditCapabilities` interface and the `apiHasEditCapabilities` type guard. The [edit panal action](https://github.com/elastic/kibana/tree/main/src/plugins/presentation_panel/public/panel_actions/edit_panel_action/edit_panel_action.ts) defines the "Edit" panel context menu action. The action's `isCompatible` check uses the `apiHasEditCapabilities` type guard to check that an embeddable API implements the `HasEditCapabilities` interface. When an embeddable API implements the interface and all other conditions of `isCompatible` check are true, the "Edit" action is availabe in the panel context menu. When an embeddable API does not implement the interface, the "Edit" action is not available in the panel context menu. + +#### Publishing subject +An embeddable API shares state via a publishing subject, a read only RxJS Observable. + +For example, [publishes_panel_title](https://github.com/elastic/kibana/tree/main/packages/presentation/presentation_publishing/interfaces/titles/publishes_panel_title.ts) publishing package defines interfaces and type guards for title state. [initializeTitles](https://github.com/elastic/kibana/tree/main/packages/presentation/presentation_publishing/interfaces/titles/titles_api.ts) provides an implemenation for the titles publishing package. `panelTitle` is provided as a publishing subject. [PresentationPanelInternal React component](https://github.com/elastic/kibana/tree/main/src/plugins/presentation_panel/public/panel_component/presentation_panel_internal.tsx) uses a hook to consume `panelTitle` as React state. Changes to `panelTitle` publishing subject updates React state, which in turn, causes the UI to re-render with the current value. [CustomizePanelEditor React component](https://github.com/elastic/kibana/tree/main/src/plugins/presentation_panel/public/panel_actions/customize_panel_action/customize_panel_editor.tsx) uses `api.setPanelTitle` to set the title on save. + +#### Comparators +Comparators allow a page to track changes to an embeddable's state. For example, Dashboard uses comparators to display a UI notification for unsaved changes, to reset changes, and persist unsaved changes to session storage. + +A comparator must be provided for each property in an embeddable's RuntimeState. A comparator is a 3 element tuple: where the first element is a publishing subject providing the current value. The second element is a setter allowing the page to reset the value. The third element is an optional comparator function which provides logic to diff this property. + +For example, [initializeTitles](https://github.com/elastic/kibana/tree/main/packages/presentation/presentation_publishing/interfaces/titles/titles_api.ts) provides an implemenation for the titles publishing package. Comparitors are provided for each property from `SerializedTitles`. + +### Best practices + +#### Do not use Embeddables to share Components between plugins +Only create an embeddable if your Component is rendered on a page that persists embeddable state and renders multiple embeddable types. For example, create an embeddable to render your Component on a Dashboard. Otherwise, use a vanilla React Component to share Components between plugins. + +#### Do not use Embeddables to avoid circular plugin dependencies +Break your Component into a Package or another plugin to avoid circular plugin dependencies. + +#### Minimal API surface area +Embeddable APIs are accessable to all Kibana systems and all embeddable siblings and parents. Functions and state that are internal to an embeddable including any child components should not be added to the API. Consider passing internal state to child as props or react context. + +### Examples -#### Examples Examples available at [/examples/embeddable_examples](https://github.com/elastic/kibana/tree/main/examples/embeddable_examples) -* [Register an embeddable](https://github.com/elastic/kibana/blob/main/examples/embeddable_examples/public/react_embeddables/search/register_search_embeddable.ts) -* [Embeddable that responds to Unified search](https://github.com/elastic/kibana/blob/main/examples/embeddable_examples/public/react_embeddables/search/search_react_embeddable.tsx) -* [Embeddable that interacts with sibling embeddables](https://github.com/elastic/kibana/blob/main/examples/embeddable_examples/public/react_embeddables/data_table/data_table_react_embeddable.tsx) -* [Render an embeddable](https://github.com/elastic/kibana/blob/main/examples/embeddable_examples/public/react_embeddables/search/search_embeddable_renderer.tsx) + +- [Register an embeddable](https://github.com/elastic/kibana/blob/main/examples/embeddable_examples/public/react_embeddables/search/register_search_embeddable.ts) +- [Embeddable that responds to Unified search](https://github.com/elastic/kibana/blob/main/examples/embeddable_examples/public/react_embeddables/search/search_react_embeddable.tsx) +- [Embeddable that interacts with sibling embeddables](https://github.com/elastic/kibana/blob/main/examples/embeddable_examples/public/react_embeddables/data_table/data_table_react_embeddable.tsx) +- [Embeddable that can be by value or by reference](https://github.com/elastic/kibana/blob/main/examples/embeddable_examples/public/react_embeddables/saved_book/saved_book_react_embeddable.tsx) +- [Render an embeddable](https://github.com/elastic/kibana/blob/main/examples/embeddable_examples/public/react_embeddables/search/search_embeddable_renderer.tsx) Run examples with `yarn start --run-examples` To access example embeddables, create a new dashboard, click "Add panel" and finally select "Embeddable examples". \ No newline at end of file diff --git a/src/plugins/embeddable/public/index.ts b/src/plugins/embeddable/public/index.ts index 7580e84f29e39..b00adeb711a5b 100644 --- a/src/plugins/embeddable/public/index.ts +++ b/src/plugins/embeddable/public/index.ts @@ -98,8 +98,6 @@ export { ReactEmbeddableRenderer, type DefaultEmbeddableApi, type ReactEmbeddableFactory, - type ReactEmbeddableRegistration, - startTrackingEmbeddableUnsavedChanges, } from './react_embeddable_system'; export function plugin(initializerContext: PluginInitializerContext) { diff --git a/src/plugins/embeddable/public/lib/containers/container.ts b/src/plugins/embeddable/public/lib/containers/container.ts index d1a15bb2588f0..d7b5f56b2202b 100644 --- a/src/plugins/embeddable/public/lib/containers/container.ts +++ b/src/plugins/embeddable/public/lib/containers/container.ts @@ -8,7 +8,7 @@ import deepEqual from 'fast-deep-equal'; import { isEqual, xor } from 'lodash'; -import { BehaviorSubject, EMPTY, merge, Subject, Subscription } from 'rxjs'; +import { BehaviorSubject, EMPTY, merge, Subscription } from 'rxjs'; import { catchError, combineLatestWith, @@ -22,7 +22,7 @@ import { import { v4 as uuidv4 } from 'uuid'; import { PanelPackage } from '@kbn/presentation-containers'; -import { PresentationContainer, SerializedPanelState } from '@kbn/presentation-containers'; +import { PresentationContainer } from '@kbn/presentation-containers'; import { isSavedObjectEmbeddableInput } from '../../../common/lib/saved_object_embeddable'; import { EmbeddableStart } from '../../plugin'; @@ -64,10 +64,6 @@ export abstract class Container< private subscription: Subscription | undefined; private readonly anyChildOutputChange$; - public lastSavedState: Subject = new Subject(); - public getLastSavedStateForChild: (childId: string) => SerializedPanelState | undefined = () => - undefined; - constructor( input: TContainerInput, output: TContainerOutput, diff --git a/src/plugins/embeddable/public/plugin.tsx b/src/plugins/embeddable/public/plugin.tsx index 334e4799ae334..771db22cdd674 100644 --- a/src/plugins/embeddable/public/plugin.tsx +++ b/src/plugins/embeddable/public/plugin.tsx @@ -58,8 +58,6 @@ import { import { getAllMigrations } from '../common/lib/get_all_migrations'; import { setKibanaServices } from './kibana_services'; import { - DefaultEmbeddableApi, - ReactEmbeddableFactory, reactEmbeddableRegistryHasKey, registerReactEmbeddableFactory, } from './react_embeddable_system'; @@ -108,13 +106,7 @@ export interface EmbeddableSetup { /** * Registers an async {@link ReactEmbeddableFactory} getter. */ - registerReactEmbeddableFactory: < - StateType extends object = object, - APIType extends DefaultEmbeddableApi = DefaultEmbeddableApi - >( - type: string, - getFactory: () => Promise> - ) => void; + registerReactEmbeddableFactory: typeof registerReactEmbeddableFactory; /** * @deprecated use {@link registerReactEmbeddableFactory} instead. diff --git a/src/plugins/embeddable/public/react_embeddable_system/index.ts b/src/plugins/embeddable/public/react_embeddable_system/index.ts index 00f77c87cb5b7..54917869508af 100644 --- a/src/plugins/embeddable/public/react_embeddable_system/index.ts +++ b/src/plugins/embeddable/public/react_embeddable_system/index.ts @@ -11,9 +11,4 @@ export { registerReactEmbeddableFactory, } from './react_embeddable_registry'; export { ReactEmbeddableRenderer } from './react_embeddable_renderer'; -export { startTrackingEmbeddableUnsavedChanges } from './react_embeddable_unsaved_changes'; -export type { - DefaultEmbeddableApi, - ReactEmbeddableFactory, - ReactEmbeddableRegistration, -} from './types'; +export type { DefaultEmbeddableApi, ReactEmbeddableFactory } from './types'; diff --git a/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_registry.ts b/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_registry.ts index 5cd245ca074cc..b1d67cc8a1d90 100644 --- a/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_registry.ts +++ b/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_registry.ts @@ -14,16 +14,17 @@ const registry: { [key: string]: () => Promise> /** * Registers a new React embeddable factory. This should be called at plugin start time. * - * @param type The key to register the factory under. This should be the same as the `type` key in the factory definition. + * @param type The key to register the factory under. * @param getFactory an async function that gets the factory definition for this key. This should always async import the * actual factory definition file to avoid polluting page load. */ export const registerReactEmbeddableFactory = < - StateType extends object = object, - APIType extends DefaultEmbeddableApi = DefaultEmbeddableApi + SerializedState extends object = object, + Api extends DefaultEmbeddableApi = DefaultEmbeddableApi, + RuntimeState extends object = SerializedState >( type: string, - getFactory: () => Promise> + getFactory: () => Promise> ) => { if (registry[type] !== undefined) throw new Error( @@ -38,11 +39,12 @@ export const registerReactEmbeddableFactory = < export const reactEmbeddableRegistryHasKey = (key: string) => registry[key] !== undefined; export const getReactEmbeddableFactory = async < - StateType extends object = object, - ApiType extends DefaultEmbeddableApi = DefaultEmbeddableApi + SerializedState extends object = object, + Api extends DefaultEmbeddableApi = DefaultEmbeddableApi, + RuntimeState extends object = SerializedState >( key: string -): Promise> => { +): Promise> => { if (registry[key] === undefined) throw new Error( i18n.translate('embeddableApi.reactEmbeddable.factoryNotFoundError', { diff --git a/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_renderer.test.tsx b/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_renderer.test.tsx index f4b9a4db43960..84cfa78e983b0 100644 --- a/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_renderer.test.tsx +++ b/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_renderer.test.tsx @@ -54,8 +54,19 @@ describe('react embeddable renderer', () => { setupPresentationPanelServices(); }); - it('deserializes given state', async () => { - render(); + it('deserializes unsaved state provided by the parent', async () => { + render( + ({ + getSerializedStateForChild: () => ({ + rawState: { + bork: 'blorp?', + }, + }), + })} + /> + ); await waitFor(() => { expect(testEmbeddableFactory.deserializeState).toHaveBeenCalledWith({ rawState: { bork: 'blorp?' }, @@ -65,13 +76,24 @@ describe('react embeddable renderer', () => { it('builds the embeddable', async () => { const buildEmbeddableSpy = jest.spyOn(testEmbeddableFactory, 'buildEmbeddable'); - render(); + render( + ({ + getSerializedStateForChild: () => ({ + rawState: { + bork: 'blorp?', + }, + }), + })} + /> + ); await waitFor(() => { expect(buildEmbeddableSpy).toHaveBeenCalledWith( { bork: 'blorp?' }, expect.any(Function), expect.any(String), - undefined + expect.any(Object) ); }); }); @@ -82,7 +104,13 @@ describe('react embeddable renderer', () => { ({ + getSerializedStateForChild: () => ({ + rawState: { + bork: 'blorp?', + }, + }), + })} /> ); await waitFor(() => { @@ -90,21 +118,22 @@ describe('react embeddable renderer', () => { { bork: 'blorp?' }, expect.any(Function), '12345', - undefined + expect.any(Object) ); }); }); it('builds the embeddable, providing a parent', async () => { const buildEmbeddableSpy = jest.spyOn(testEmbeddableFactory, 'buildEmbeddable'); - const parentApi = getMockPresentationContainer(); - render( - - ); + const parentApi = { + ...getMockPresentationContainer(), + getSerializedStateForChild: () => ({ + rawState: { + bork: 'blorp?', + }, + }), + }; + render( parentApi} />); await waitFor(() => { expect(buildEmbeddableSpy).toHaveBeenCalledWith( { bork: 'blorp?' }, @@ -119,7 +148,11 @@ describe('react embeddable renderer', () => { render( ({ + getSerializedStateForChild: () => ({ + rawState: { name: 'Kuni Garu', bork: 'Dara' }, + }), + })} /> ); await waitFor(() => { @@ -136,17 +169,22 @@ describe('react embeddable renderer', () => { type={'test'} maybeId={'12345'} onApiAvailable={onApiAvailable} - state={{ rawState: { name: 'Kuni Garu' } }} + getParentApi={() => ({ + getSerializedStateForChild: () => ({ + rawState: { name: 'Kuni Garu' }, + }), + })} /> ); await waitFor(() => expect(onApiAvailable).toHaveBeenCalledWith({ type: 'test', uuid: '12345', - parentApi: undefined, + parentApi: expect.any(Object), unsavedChanges: expect.any(Object), serializeState: expect.any(Function), resetUnsavedChanges: expect.any(Function), + snapshotRuntimeState: expect.any(Function), }) ); }); @@ -157,7 +195,11 @@ describe('react embeddable renderer', () => { ({ + getSerializedStateForChild: () => ({ + rawState: { name: 'Kuni Garu' }, + }), + })} /> ); await waitFor(() => diff --git a/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx b/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx index 45cb648e1b626..98a7a42244bb4 100644 --- a/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx +++ b/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx @@ -6,14 +6,14 @@ * Side Public License, v 1. */ -import { SerializedPanelState } from '@kbn/presentation-containers'; +import { HasSerializedChildState, SerializedPanelState } from '@kbn/presentation-containers'; import { PresentationPanel, PresentationPanelProps } from '@kbn/presentation-panel-plugin/public'; import { ComparatorDefinition, StateComparators } from '@kbn/presentation-publishing'; import React, { useEffect, useImperativeHandle, useMemo, useRef } from 'react'; -import { combineLatest, debounceTime, skip } from 'rxjs'; +import { combineLatest, debounceTime, skip, switchMap } from 'rxjs'; import { v4 as generateId } from 'uuid'; import { getReactEmbeddableFactory } from './react_embeddable_registry'; -import { startTrackingEmbeddableUnsavedChanges } from './react_embeddable_unsaved_changes'; +import { initializeReactEmbeddableState } from './react_embeddable_state'; import { DefaultEmbeddableApi, ReactEmbeddableApiRegistration } from './types'; const ON_STATE_CHANGE_DEBOUNCE = 100; @@ -24,25 +24,25 @@ const ON_STATE_CHANGE_DEBOUNCE = 100; * TODO: Rename this to simply `Embeddable` when the legacy Embeddable system is removed. */ export const ReactEmbeddableRenderer = < - StateType extends object = object, - ApiType extends DefaultEmbeddableApi = DefaultEmbeddableApi + SerializedState extends object = object, + Api extends DefaultEmbeddableApi = DefaultEmbeddableApi, + RuntimeState extends object = SerializedState, + ParentApi extends HasSerializedChildState = HasSerializedChildState >({ - maybeId, type, - state, - parentApi, - onApiAvailable, + maybeId, + getParentApi, panelProps, onAnyStateChange, + onApiAvailable, hidePanelChrome, }: { - maybeId?: string; type: string; - state: SerializedPanelState; - parentApi?: unknown; - onApiAvailable?: (api: ApiType) => void; + maybeId?: string; + getParentApi: () => ParentApi; + onApiAvailable?: (api: Api) => void; panelProps?: Pick< - PresentationPanelProps, + PresentationPanelProps, | 'showShadow' | 'showBorder' | 'showBadges' @@ -55,57 +55,73 @@ export const ReactEmbeddableRenderer = < * This `onAnyStateChange` callback allows the parent to keep track of the state of the embeddable * as it changes. This is **not** expected to change over the lifetime of the component. */ - onAnyStateChange?: (state: SerializedPanelState) => void; + onAnyStateChange?: (state: SerializedPanelState) => void; }) => { const cleanupFunction = useRef<(() => void) | null>(null); const componentPromise = useMemo( () => (async () => { + const parentApi = getParentApi(); const uuid = maybeId ?? generateId(); - const factory = await getReactEmbeddableFactory(type); - const registerApi = ( - apiRegistration: ReactEmbeddableApiRegistration, - comparators: StateComparators - ) => { - const { unsavedChanges, resetUnsavedChanges, cleanup } = - startTrackingEmbeddableUnsavedChanges( - uuid, - parentApi, - comparators, - factory.deserializeState - ); + const factory = await getReactEmbeddableFactory(type); + + const { initialState, startStateDiffing } = await initializeReactEmbeddableState< + SerializedState, + Api, + RuntimeState + >(uuid, factory, parentApi); + const buildApi = ( + apiRegistration: ReactEmbeddableApiRegistration, + comparators: StateComparators + ) => { if (onAnyStateChange) { /** * To avoid unnecessary re-renders, only subscribe to the comparator publishing subjects if * an `onAnyStateChange` callback is provided */ - const comparatorDefinitions: Array> = - Object.values(comparators); + const comparatorDefinitions: Array< + ComparatorDefinition + > = Object.values(comparators); combineLatest(comparatorDefinitions.map((comparator) => comparator[0])) - .pipe(skip(1), debounceTime(ON_STATE_CHANGE_DEBOUNCE)) - .subscribe(() => { - onAnyStateChange(apiRegistration.serializeState()); + .pipe( + skip(1), + debounceTime(ON_STATE_CHANGE_DEBOUNCE), + switchMap(() => { + const isAsync = + apiRegistration.serializeState.prototype?.name === 'AsyncFunction'; + return isAsync + ? (apiRegistration.serializeState() as Promise< + SerializedPanelState + >) + : Promise.resolve(apiRegistration.serializeState()); + }) + ) + .subscribe((serializedState) => { + onAnyStateChange(serializedState); }); } + const { unsavedChanges, resetUnsavedChanges, cleanup, snapshotRuntimeState } = + startStateDiffing(comparators); const fullApi = { ...apiRegistration, uuid, parentApi, unsavedChanges, - resetUnsavedChanges, type: factory.type, - } as unknown as ApiType; + resetUnsavedChanges, + snapshotRuntimeState, + } as unknown as Api; cleanupFunction.current = () => cleanup(); onApiAvailable?.(fullApi); return fullApi; }; const { api, Component } = await factory.buildEmbeddable( - factory.deserializeState(state), - registerApi, + initialState, + buildApi, uuid, parentApi ); @@ -132,7 +148,7 @@ export const ReactEmbeddableRenderer = < }, []); return ( - + hidePanelChrome={hidePanelChrome} {...panelProps} Component={componentPromise} diff --git a/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_unsaved_changes.test.tsx b/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_state.test.ts similarity index 54% rename from src/plugins/embeddable/public/react_embeddable_system/react_embeddable_unsaved_changes.test.tsx rename to src/plugins/embeddable/public/react_embeddable_system/react_embeddable_state.test.ts index c230e7a3840a6..6f34b4f04bffd 100644 --- a/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_unsaved_changes.test.tsx +++ b/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_state.test.ts @@ -7,15 +7,17 @@ */ import { + HasRuntimeChildState, + HasSaveNotification, + HasSerializedChildState, PresentationContainer, - PublishesLastSavedState, - SerializedPanelState, } from '@kbn/presentation-containers'; import { getMockPresentationContainer } from '@kbn/presentation-containers/mocks'; import { StateComparators } from '@kbn/presentation-publishing'; import { waitFor } from '@testing-library/react'; import { BehaviorSubject, Subject } from 'rxjs'; -import { startTrackingEmbeddableUnsavedChanges } from './react_embeddable_unsaved_changes'; +import { initializeReactEmbeddableState } from './react_embeddable_state'; +import { ReactEmbeddableFactory } from './types'; interface SuperTestStateType { name: string; @@ -24,29 +26,36 @@ interface SuperTestStateType { } describe('react embeddable unsaved changes', () => { - let initialState: SuperTestStateType; - let lastSavedState: SuperTestStateType; + let serializedStateForChild: SuperTestStateType; + let comparators: StateComparators; - let deserializeState: (state: SerializedPanelState) => SuperTestStateType; - let parentApi: (PresentationContainer & PublishesLastSavedState) | null; + let parentApi: PresentationContainer & + HasSerializedChildState & + Partial> & + HasSaveNotification; beforeEach(() => { - initialState = { + serializedStateForChild = { name: 'Sir Testsalot', age: 42, - tagline: 'A glutton for testing!', + tagline: `Oh he's a glutton for testing!`, }; - lastSavedState = { - name: 'Sir Testsalot', - age: 42, - tagline: 'A glutton for testing!', + parentApi = { + saveNotification$: new Subject(), + ...getMockPresentationContainer(), + getSerializedStateForChild: () => ({ rawState: serializedStateForChild }), + getRuntimeStateForChild: () => undefined, }; }); const initializeDefaultComparators = () => { - const nameSubject = new BehaviorSubject(initialState.name); - const ageSubject = new BehaviorSubject(initialState.age); - const taglineSubject = new BehaviorSubject(initialState.tagline); + const latestState: SuperTestStateType = { + ...serializedStateForChild, + ...(parentApi.getRuntimeStateForChild?.('uuid') ?? {}), + }; + const nameSubject = new BehaviorSubject(latestState.name); + const ageSubject = new BehaviorSubject(latestState.age); + const taglineSubject = new BehaviorSubject(latestState.tagline); const defaultComparators: StateComparators = { name: [nameSubject, jest.fn((nextName) => nameSubject.next(nextName))], age: [ageSubject, jest.fn((nextAge) => ageSubject.next(nextAge))], @@ -55,49 +64,58 @@ describe('react embeddable unsaved changes', () => { return defaultComparators; }; - const startTrackingUnsavedChanges = ( + const startTrackingUnsavedChanges = async ( customComparators?: StateComparators ) => { comparators = customComparators ?? initializeDefaultComparators(); - deserializeState = jest.fn((state) => state.rawState as SuperTestStateType); - parentApi = { - ...getMockPresentationContainer(), - getLastSavedStateForChild: () => ({ - rawState: lastSavedState as SerializedState, - }), - lastSavedState: new Subject(), + const factory: ReactEmbeddableFactory = { + type: 'superTest', + deserializeState: jest.fn().mockImplementation((state) => state.rawState), + buildEmbeddable: async (runtimeState, buildApi) => { + const api = buildApi({ serializeState: jest.fn() }, comparators); + return { api, Component: () => null }; + }, }; - return startTrackingEmbeddableUnsavedChanges('id', parentApi, comparators, deserializeState); + const { startStateDiffing } = await initializeReactEmbeddableState('uuid', factory, parentApi); + return startStateDiffing(comparators); }; - it('should return undefined unsaved changes when used without a parent context to provide the last saved state', async () => { - parentApi = null; - const unsavedChangesApi = startTrackingUnsavedChanges(); + it('should return undefined unsaved changes when parent API does not provide runtime state', async () => { + const unsavedChangesApi = await startTrackingUnsavedChanges(); + parentApi.getRuntimeStateForChild = undefined; expect(unsavedChangesApi).toBeDefined(); expect(unsavedChangesApi.unsavedChanges.value).toBe(undefined); }); - it('runs factory deserialize function on last saved state', async () => { - startTrackingUnsavedChanges(); - expect(deserializeState).toHaveBeenCalledWith({ rawState: lastSavedState }); + it('should return undefined unsaved changes when parent API does not have runtime state for this child', async () => { + const unsavedChangesApi = await startTrackingUnsavedChanges(); + // no change here becuase getRuntimeStateForChild already returns undefined + expect(unsavedChangesApi.unsavedChanges.value).toBe(undefined); }); it('should return unsaved changes subject initialized to undefined when no unsaved changes are detected', async () => { - const unsavedChangesApi = startTrackingUnsavedChanges(); + parentApi.getRuntimeStateForChild = () => ({ + name: 'Sir Testsalot', + age: 42, + tagline: `Oh he's a glutton for testing!`, + }); + const unsavedChangesApi = await startTrackingUnsavedChanges(); expect(unsavedChangesApi.unsavedChanges.value).toBe(undefined); }); it('should return unsaved changes subject initialized with diff when unsaved changes are detected', async () => { - initialState.tagline = 'Testing is my speciality!'; - const unsavedChangesApi = startTrackingUnsavedChanges(); + parentApi.getRuntimeStateForChild = () => ({ + tagline: 'Testing is my speciality!', + }); + const unsavedChangesApi = await startTrackingUnsavedChanges(); expect(unsavedChangesApi.unsavedChanges.value).toEqual({ tagline: 'Testing is my speciality!', }); }); it('should detect unsaved changes when state changes during the lifetime of the component', async () => { - const unsavedChangesApi = startTrackingUnsavedChanges(); + const unsavedChangesApi = await startTrackingUnsavedChanges(); expect(unsavedChangesApi.unsavedChanges.value).toBe(undefined); comparators.tagline[1]('Testing is my speciality!'); @@ -108,22 +126,25 @@ describe('react embeddable unsaved changes', () => { }); }); - it('should detect unsaved changes when last saved state changes during the lifetime of the component', async () => { - const unsavedChangesApi = startTrackingUnsavedChanges(); + it('current runtime state should become last saved state when parent save notification is triggered', async () => { + const unsavedChangesApi = await startTrackingUnsavedChanges(); expect(unsavedChangesApi.unsavedChanges.value).toBe(undefined); - lastSavedState.tagline = 'Some other tagline'; - parentApi?.lastSavedState.next(); + comparators.tagline[1]('Testing is my speciality!'); await waitFor(() => { expect(unsavedChangesApi.unsavedChanges.value).toEqual({ - // we expect `A glutton for testing!` here because that is the current state of the component. - tagline: 'A glutton for testing!', + tagline: 'Testing is my speciality!', }); }); + + parentApi.saveNotification$.next(); + await waitFor(() => { + expect(unsavedChangesApi.unsavedChanges.value).toBe(undefined); + }); }); it('should reset unsaved changes, calling given setters with last saved values. This should remove all unsaved state', async () => { - const unsavedChangesApi = startTrackingUnsavedChanges(); + const unsavedChangesApi = await startTrackingUnsavedChanges(); expect(unsavedChangesApi.unsavedChanges.value).toBe(undefined); comparators.tagline[1]('Testing is my speciality!'); @@ -134,16 +155,18 @@ describe('react embeddable unsaved changes', () => { }); unsavedChangesApi.resetUnsavedChanges(); - expect(comparators.tagline[1]).toHaveBeenCalledWith('A glutton for testing!'); + expect(comparators.tagline[1]).toHaveBeenCalledWith(`Oh he's a glutton for testing!`); await waitFor(() => { expect(unsavedChangesApi.unsavedChanges.value).toBe(undefined); }); }); it('uses a custom comparator when supplied', async () => { - lastSavedState.age = 20; - initialState.age = 50; - const ageSubject = new BehaviorSubject(initialState.age); + serializedStateForChild.age = 20; + parentApi.getRuntimeStateForChild = () => ({ + age: 50, + }); + const ageSubject = new BehaviorSubject(50); const customComparators: StateComparators = { ...initializeDefaultComparators(), age: [ @@ -153,7 +176,7 @@ describe('react embeddable unsaved changes', () => { ], }; - const unsavedChangesApi = startTrackingUnsavedChanges(customComparators); + const unsavedChangesApi = await startTrackingUnsavedChanges(customComparators); // here we expect there to be no unsaved changes, both unsaved state and last saved state have two digits. expect(unsavedChangesApi.unsavedChanges.value).toBe(undefined); diff --git a/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_state.ts b/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_state.ts new file mode 100644 index 0000000000000..605b8d20a7cd1 --- /dev/null +++ b/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_state.ts @@ -0,0 +1,120 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { + apiHasRuntimeChildState, + apiHasSaveNotification, + HasSerializedChildState, +} from '@kbn/presentation-containers'; +import { + getInitialValuesFromComparators, + PublishingSubject, + runComparators, + StateComparators, +} from '@kbn/presentation-publishing'; +import { + BehaviorSubject, + combineLatest, + combineLatestWith, + debounceTime, + map, + Subscription, +} from 'rxjs'; +import { DefaultEmbeddableApi, ReactEmbeddableFactory } from './types'; + +export const initializeReactEmbeddableState = async < + SerializedState extends object = object, + Api extends DefaultEmbeddableApi = DefaultEmbeddableApi, + RuntimeState extends object = SerializedState +>( + uuid: string, + factory: ReactEmbeddableFactory, + parentApi: HasSerializedChildState +) => { + const lastSavedRuntimeState = await factory.deserializeState( + parentApi.getSerializedStateForChild(uuid) + ); + + // If the parent provides runtime state for the child (usually as a state backup or cache), + // we merge it with the last saved runtime state. + const partialRuntimeState = apiHasRuntimeChildState(parentApi) + ? parentApi.getRuntimeStateForChild(uuid) ?? ({} as Partial) + : ({} as Partial); + + const initialRuntimeState = { ...lastSavedRuntimeState, ...partialRuntimeState }; + + const startStateDiffing = (comparators: StateComparators) => { + const subscription = new Subscription(); + const snapshotRuntimeState = () => { + const comparatorKeys = Object.keys(comparators) as Array; + return comparatorKeys.reduce((acc, key) => { + acc[key] = comparators[key][0].value as RuntimeState[typeof key]; + return acc; + }, {} as RuntimeState); + }; + + // the last saved state subject is always initialized with the deserialized state from the parent. + const lastSavedState$ = new BehaviorSubject(lastSavedRuntimeState); + if (apiHasSaveNotification(parentApi)) { + subscription.add( + // any time the parent saves, the current state becomes the last saved state... + parentApi.saveNotification$.subscribe(() => { + lastSavedState$.next(snapshotRuntimeState()); + }) + ); + } + + const comparatorSubjects: Array> = []; + const comparatorKeys: Array = []; + for (const key of Object.keys(comparators) as Array) { + const comparatorSubject = comparators[key][0]; // 0th element of tuple is the subject + comparatorSubjects.push(comparatorSubject as PublishingSubject); + comparatorKeys.push(key); + } + + const unsavedChanges = new BehaviorSubject | undefined>( + runComparators( + comparators, + comparatorKeys, + lastSavedState$.getValue() as RuntimeState, + getInitialValuesFromComparators(comparators, comparatorKeys) + ) + ); + + subscription.add( + combineLatest(comparatorSubjects) + .pipe( + debounceTime(100), + map((latestStates) => + comparatorKeys.reduce((acc, key, index) => { + acc[key] = latestStates[index] as RuntimeState[typeof key]; + return acc; + }, {} as Partial) + ), + combineLatestWith(lastSavedState$) + ) + .subscribe(([latest, last]) => { + unsavedChanges.next(runComparators(comparators, comparatorKeys, last, latest)); + }) + ); + return { + unsavedChanges, + resetUnsavedChanges: () => { + const lastSaved = lastSavedState$.getValue(); + for (const key of comparatorKeys) { + const setter = comparators[key][1]; // setter function is the 1st element of the tuple + setter(lastSaved?.[key] as RuntimeState[typeof key]); + } + }, + snapshotRuntimeState, + cleanup: () => subscription.unsubscribe(), + }; + }; + + return { initialState: initialRuntimeState, startStateDiffing }; +}; diff --git a/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_unsaved_changes.ts b/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_unsaved_changes.ts deleted file mode 100644 index 4df8bd9df287a..0000000000000 --- a/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_unsaved_changes.ts +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 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 { - getLastSavedStateSubjectForChild, - SerializedPanelState, -} from '@kbn/presentation-containers'; -import { - getInitialValuesFromComparators, - PublishingSubject, - runComparators, - StateComparators, -} from '@kbn/presentation-publishing'; -import { BehaviorSubject, combineLatest } from 'rxjs'; -import { combineLatestWith, debounceTime, map } from 'rxjs'; - -const getDefaultDiffingApi = () => { - return { - unsavedChanges: new BehaviorSubject(undefined), - resetUnsavedChanges: () => {}, - cleanup: () => {}, - }; -}; - -export const startTrackingEmbeddableUnsavedChanges = < - SerializedState extends object = object, - RuntimeState extends object = object ->( - uuid: string, - parentApi: unknown, - comparators: StateComparators, - deserializeState: (state: SerializedPanelState) => RuntimeState -) => { - if (Object.keys(comparators).length === 0) return getDefaultDiffingApi(); - - const lastSavedStateSubject = getLastSavedStateSubjectForChild( - parentApi, - uuid, - deserializeState - ); - if (!lastSavedStateSubject) return getDefaultDiffingApi(); - - const comparatorSubjects: Array> = []; - const comparatorKeys: Array = []; - for (const key of Object.keys(comparators) as Array) { - const comparatorSubject = comparators[key][0]; // 0th element of tuple is the subject - comparatorSubjects.push(comparatorSubject as PublishingSubject); - comparatorKeys.push(key); - } - - const unsavedChanges = new BehaviorSubject | undefined>( - runComparators( - comparators, - comparatorKeys, - lastSavedStateSubject?.getValue(), - getInitialValuesFromComparators(comparators, comparatorKeys) - ) - ); - - const subscription = combineLatest(comparatorSubjects) - .pipe( - debounceTime(100), - map((latestStates) => - comparatorKeys.reduce((acc, key, index) => { - acc[key] = latestStates[index] as RuntimeState[typeof key]; - return acc; - }, {} as Partial) - ), - combineLatestWith(lastSavedStateSubject) - ) - .subscribe(([latestStates, lastSavedState]) => { - unsavedChanges.next( - runComparators(comparators, comparatorKeys, lastSavedState, latestStates) - ); - }); - - return { - unsavedChanges, - resetUnsavedChanges: () => { - const lastSaved = lastSavedStateSubject?.getValue(); - for (const key of comparatorKeys) { - const setter = comparators[key][1]; // setter function is the 1st element of the tuple - setter(lastSaved?.[key] as RuntimeState[typeof key]); - } - }, - cleanup: () => subscription.unsubscribe(), - }; -}; diff --git a/src/plugins/embeddable/public/react_embeddable_system/types.ts b/src/plugins/embeddable/public/react_embeddable_system/types.ts index 89b2ac3d98af4..f0ff899f5df69 100644 --- a/src/plugins/embeddable/public/react_embeddable_system/types.ts +++ b/src/plugins/embeddable/public/react_embeddable_system/types.ts @@ -5,34 +5,41 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import { HasSerializableState, SerializedPanelState } from '@kbn/presentation-containers'; +import { + HasSerializableState, + HasSnapshottableState, + SerializedPanelState, +} from '@kbn/presentation-containers'; import { DefaultPresentationPanelApi } from '@kbn/presentation-panel-plugin/public/panel_component/types'; import { HasType, PublishesUnsavedChanges, StateComparators } from '@kbn/presentation-publishing'; -import React, { ReactElement } from 'react'; - -export type ReactEmbeddableRegistration< - ApiType extends DefaultEmbeddableApi = DefaultEmbeddableApi -> = (ref: React.ForwardedRef) => ReactElement | null; +import { MaybePromise } from '@kbn/utility-types'; +import React from 'react'; /** * The default embeddable API that all Embeddables must implement. * * Before adding anything to this interface, please be certain that it belongs in *every* embeddable. */ -export interface DefaultEmbeddableApi - extends DefaultPresentationPanelApi, +export interface DefaultEmbeddableApi< + SerializedState extends object = object, + RuntimeState extends object = SerializedState +> extends DefaultPresentationPanelApi, HasType, PublishesUnsavedChanges, - HasSerializableState {} + HasSerializableState, + HasSnapshottableState {} /** * A subset of the default embeddable API used in registration to allow implementors to omit aspects * of the API that will be automatically added by the system. */ export type ReactEmbeddableApiRegistration< - StateType extends object = object, - ApiType extends DefaultEmbeddableApi = DefaultEmbeddableApi -> = Omit; + SerializedState extends object = object, + Api extends DefaultEmbeddableApi = DefaultEmbeddableApi +> = Omit< + Api, + 'uuid' | 'parent' | 'type' | 'unsavedChanges' | 'resetUnsavedChanges' | 'snapshotRuntimeState' +>; /** * The React Embeddable Factory interface is used to register a series of functions that @@ -43,7 +50,7 @@ export type ReactEmbeddableApiRegistration< **/ export interface ReactEmbeddableFactory< SerializedState extends object = object, - ApiType extends DefaultEmbeddableApi = DefaultEmbeddableApi, + Api extends DefaultEmbeddableApi = DefaultEmbeddableApi, RuntimeState extends object = SerializedState > { /** @@ -53,16 +60,16 @@ export interface ReactEmbeddableFactory< type: string; /** - * A required synchronous function that transforms serialized state into runtime state. - * This will be used twice - once for the parent state, and once for the last saved state - * for comparison. - * - * This can also be used to: + * A required asynchronous function that transforms serialized state into runtime state. * + * This could be used to: + * - Load state from some external store * - Inject references provided by the parent * - Migrate the state to a newer version (this must be undone when serializing) */ - deserializeState: (state: SerializedPanelState) => RuntimeState; + deserializeState: ( + panelState: SerializedPanelState + ) => MaybePromise; /** * A required async function that builds your embeddable component and a linked API instance. The API @@ -75,10 +82,10 @@ export interface ReactEmbeddableFactory< buildEmbeddable: ( initialState: RuntimeState, buildApi: ( - apiRegistration: ReactEmbeddableApiRegistration, + apiRegistration: ReactEmbeddableApiRegistration, comparators: StateComparators - ) => ApiType, + ) => Api, uuid: string, parentApi?: unknown - ) => Promise<{ Component: React.FC<{}>; api: ApiType }>; + ) => Promise<{ Component: React.FC<{}>; api: Api }>; } diff --git a/src/plugins/guided_onboarding/kibana.jsonc b/src/plugins/guided_onboarding/kibana.jsonc index 6dd0d9f80a436..1bbdc9d1003c1 100644 --- a/src/plugins/guided_onboarding/kibana.jsonc +++ b/src/plugins/guided_onboarding/kibana.jsonc @@ -1,7 +1,7 @@ { "type": "plugin", "id": "@kbn/guided-onboarding-plugin", - "owner": "@elastic/platform-onboarding", + "owner": "@elastic/appex-sharedux", "description": "Guided onboarding framework", "plugin": { "id": "guidedOnboarding", diff --git a/src/plugins/input_control_vis/public/input_control_vis_renderer.tsx b/src/plugins/input_control_vis/public/input_control_vis_renderer.tsx index 4f0c5f1c2f4f4..7c86de1fe1e0b 100644 --- a/src/plugins/input_control_vis/public/input_control_vis_renderer.tsx +++ b/src/plugins/input_control_vis/public/input_control_vis_renderer.tsx @@ -19,12 +19,13 @@ export const getInputControlVisRenderer: ( name: 'input_control_vis', reuseDomNode: true, render: async (domNode, { visConfig }, handlers) => { + const [coreStart] = await deps.core.getStartServices(); let registeredController = inputControlVisRegistry.get(domNode); if (!registeredController) { const { createInputControlVisController } = await import('./vis_controller'); - registeredController = createInputControlVisController(deps, handlers, domNode); + registeredController = createInputControlVisController(coreStart, deps, handlers, domNode); inputControlVisRegistry.set(domNode, registeredController); handlers.onDestroy(() => { diff --git a/src/plugins/input_control_vis/public/vis_controller.tsx b/src/plugins/input_control_vis/public/vis_controller.tsx index 0bf6f0d0754a9..df02fca8ecf49 100644 --- a/src/plugins/input_control_vis/public/vis_controller.tsx +++ b/src/plugins/input_control_vis/public/vis_controller.tsx @@ -11,11 +11,12 @@ import { isEqual } from 'lodash'; import { render, unmountComponentAtNode } from 'react-dom'; import { Subscription } from 'rxjs'; -import { I18nStart } from '@kbn/core/public'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import { IInterpreterRenderHandlers } from '@kbn/expressions-plugin/common'; import { Filter } from '@kbn/es-query'; import { VisualizationContainer } from '@kbn/visualizations-plugin/public'; import { FilterManager } from '@kbn/data-plugin/public'; +import { CoreStart } from '@kbn/core/public'; import { InputControlVis } from './components/vis/input_control_vis'; import { getControlFactory } from './control/control_factory'; @@ -28,11 +29,11 @@ import { InputControlVisParams } from './types'; export type InputControlVisControllerType = ReturnType; export const createInputControlVisController = ( + coreStart: CoreStart, deps: InputControlVisDependencies, handlers: IInterpreterRenderHandlers, el: Element ) => { - let I18nContext: I18nStart['Context'] | undefined; let isLoaded = false; return new (class InputControlVisController { @@ -65,10 +66,6 @@ export const createInputControlVisController = ( } async render(visParams: InputControlVisParams) { - if (!I18nContext) { - const [{ i18n }] = await deps.core.getStartServices(); - I18nContext = i18n.Context; - } if (!isLoaded || !isEqual(visParams, this.visParams)) { this.visParams = visParams; this.controls = []; @@ -86,12 +83,8 @@ export const createInputControlVisController = ( } drawVis = () => { - if (!I18nContext) { - throw new Error('no i18n context found'); - } - render( - + - , + , el ); }; diff --git a/src/plugins/input_control_vis/tsconfig.json b/src/plugins/input_control_vis/tsconfig.json index 5e6020990edd3..5b4900ad1845c 100644 --- a/src/plugins/input_control_vis/tsconfig.json +++ b/src/plugins/input_control_vis/tsconfig.json @@ -26,6 +26,7 @@ "@kbn/ui-actions-plugin", "@kbn/embeddable-plugin", "@kbn/presentation-publishing", + "@kbn/react-kibana-context-render", ], "exclude": [ "target/**/*", diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts index 9c4e025dd92b5..3a81a37dba189 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts @@ -492,6 +492,10 @@ export const stackManagementSchema: MakeSchemaFrom = { type: 'boolean', _meta: { description: 'Non-default value of setting.' }, }, + 'observability:aiAssistantSearchConnectorIndexPattern': { + type: 'text', + _meta: { description: 'Non-default value of setting.' }, + }, 'observability:logsExplorer:allowedDataViews': { type: 'array', items: { diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts index e3b84245ce3f0..82f31eb629a89 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts @@ -56,6 +56,7 @@ export interface UsageStats { 'observability:aiAssistantLogsIndexPattern': string; 'observability:aiAssistantResponseLanguage': string; 'observability:aiAssistantSimulatedFunctionCalling': boolean; + 'observability:aiAssistantSearchConnectorIndexPattern': string; 'visualization:heatmap:maxBuckets': number; 'visualization:colorMapping': string; 'visualization:useLegacyTimeAxis': boolean; diff --git a/src/plugins/navigation/public/index.ts b/src/plugins/navigation/public/index.ts index 2961c09e33da8..4a26bc6552ad3 100644 --- a/src/plugins/navigation/public/index.ts +++ b/src/plugins/navigation/public/index.ts @@ -20,6 +20,7 @@ export type { NavigationPublicSetup as NavigationPublicPluginSetup, NavigationPublicStart as NavigationPublicPluginStart, SolutionType, + AddSolutionNavigationArg, } from './types'; // Export plugin after all other imports diff --git a/src/plugins/navigation/public/plugin.test.ts b/src/plugins/navigation/public/plugin.test.ts index 07de4ff3483a5..6733a54cdc18b 100644 --- a/src/plugins/navigation/public/plugin.test.ts +++ b/src/plugins/navigation/public/plugin.test.ts @@ -139,7 +139,7 @@ describe('Navigation Plugin', () => { expect(coreStart.chrome.project.updateSolutionNavigations).toHaveBeenCalled(); const [arg] = coreStart.chrome.project.updateSolutionNavigations.mock.calls[0]; - expect(Object.keys(arg)).toEqual(['es', 'oblt']); + expect(Object.keys(arg)).toEqual(['oblt']); expect(coreStart.chrome.project.changeActiveSolutionNavigation).toHaveBeenCalledWith(null); }); diff --git a/src/plugins/navigation/public/plugin.tsx b/src/plugins/navigation/public/plugin.tsx index e62eb5c2c104f..2a36bc8e980ed 100644 --- a/src/plugins/navigation/public/plugin.tsx +++ b/src/plugins/navigation/public/plugin.tsx @@ -30,7 +30,6 @@ import type { SolutionNavigationDefinitions, } from '@kbn/core-chrome-browser'; import { InternalChromeStart } from '@kbn/core-chrome-browser-internal'; -import { definition as esDefinition } from '@kbn/solution-nav-es'; import { definition as obltDefinition } from '@kbn/solution-nav-oblt'; import type { PanelContentProvider } from '@kbn/shared-ux-chrome-navigation'; import { UserProfileData } from '@kbn/user-profile-components'; @@ -271,10 +270,6 @@ export class NavigationPublicPlugin private addDefaultSolutionNavigation({ chrome }: { chrome: InternalChromeStart }) { const solutionNavs: SolutionNavigationDefinitions = { - es: { - ...esDefinition, - sideNavComponent: this.getSideNavComponent({ dataTestSubj: 'searchSideNav' }), - }, oblt: { ...obltDefinition, sideNavComponent: this.getSideNavComponent({ dataTestSubj: 'observabilitySideNav' }), diff --git a/src/plugins/navigation/tsconfig.json b/src/plugins/navigation/tsconfig.json index 10818f045be04..8e96cf02c92ba 100644 --- a/src/plugins/navigation/tsconfig.json +++ b/src/plugins/navigation/tsconfig.json @@ -24,7 +24,6 @@ "@kbn/config-schema", "@kbn/core-plugins-server", "@kbn/i18n", - "@kbn/solution-nav-es", "@kbn/solution-nav-oblt", "@kbn/config", "@kbn/security-plugin", diff --git a/src/plugins/saved_objects_finder/public/finder/saved_object_finder.tsx b/src/plugins/saved_objects_finder/public/finder/saved_object_finder.tsx index 034f63083be1d..99e64ee919d8c 100644 --- a/src/plugins/saved_objects_finder/public/finder/saved_object_finder.tsx +++ b/src/plugins/saved_objects_finder/public/finder/saved_object_finder.tsx @@ -16,13 +16,13 @@ import type { IUiSettingsClient } from '@kbn/core/public'; import { EuiFlexGroup, EuiFlexItem, - EuiIcon, EuiInMemoryTable, EuiLink, EuiSearchBarProps, EuiTableFieldDataColumnType, EuiText, EuiToolTip, + EuiIconTip, IconType, PropertySort, Query, @@ -255,14 +255,14 @@ export class SavedObjectFinderUi extends React.Component< ).getIconForSavedObject(item.simple); return ( - - - + ); }, } diff --git a/src/plugins/saved_search/common/content_management/v1/cm_services.ts b/src/plugins/saved_search/common/content_management/v1/cm_services.ts index bc9d18b21e5b7..ef9d24bb8722d 100644 --- a/src/plugins/saved_search/common/content_management/v1/cm_services.ts +++ b/src/plugins/saved_search/common/content_management/v1/cm_services.ts @@ -42,7 +42,11 @@ const savedSearchAttributesSchema = schema.object( searchSourceJSON: schema.string(), }), viewMode: schema.maybe( - schema.oneOf([schema.literal('documents'), schema.literal('aggregated')]) + schema.oneOf([ + schema.literal('documents'), + schema.literal('patterns'), + schema.literal('aggregated'), + ]) ), hideAggregatedPreview: schema.maybe(schema.boolean()), rowHeight: schema.maybe(schema.number()), diff --git a/src/plugins/saved_search/common/index.ts b/src/plugins/saved_search/common/index.ts index 0ac92232fb3b8..f0569a86ca39a 100644 --- a/src/plugins/saved_search/common/index.ts +++ b/src/plugins/saved_search/common/index.ts @@ -19,6 +19,7 @@ export type { export enum VIEW_MODE { DOCUMENT_LEVEL = 'documents', AGGREGATED_LEVEL = 'aggregated', + PATTERN_LEVEL = 'patterns', } export { diff --git a/src/plugins/saved_search/server/saved_objects/schema.ts b/src/plugins/saved_search/server/saved_objects/schema.ts index fb0308915fe72..125ddcceb320c 100644 --- a/src/plugins/saved_search/server/saved_objects/schema.ts +++ b/src/plugins/saved_search/server/saved_objects/schema.ts @@ -119,3 +119,13 @@ export const SCHEMA_SEARCH_MODEL_VERSION_3 = SCHEMA_SEARCH_MODEL_VERSION_2.exten ]) ), }); + +export const SCHEMA_SEARCH_MODEL_VERSION_4 = SCHEMA_SEARCH_MODEL_VERSION_3.extends({ + viewMode: schema.maybe( + schema.oneOf([ + schema.literal(VIEW_MODE.DOCUMENT_LEVEL), + schema.literal(VIEW_MODE.PATTERN_LEVEL), + schema.literal(VIEW_MODE.AGGREGATED_LEVEL), + ]) + ), +}); diff --git a/src/plugins/saved_search/server/saved_objects/search.ts b/src/plugins/saved_search/server/saved_objects/search.ts index 6c6a9bb81c1ed..925a4dd66b180 100644 --- a/src/plugins/saved_search/server/saved_objects/search.ts +++ b/src/plugins/saved_search/server/saved_objects/search.ts @@ -15,6 +15,7 @@ import { SCHEMA_SEARCH_MODEL_VERSION_1, SCHEMA_SEARCH_MODEL_VERSION_2, SCHEMA_SEARCH_MODEL_VERSION_3, + SCHEMA_SEARCH_MODEL_VERSION_4, } from './schema'; export function getSavedSearchObjectType( @@ -62,6 +63,13 @@ export function getSavedSearchObjectType( create: SCHEMA_SEARCH_MODEL_VERSION_3, }, }, + 4: { + changes: [], + schemas: { + forwardCompatibility: SCHEMA_SEARCH_MODEL_VERSION_4.extends({}, { unknowns: 'ignore' }), + create: SCHEMA_SEARCH_MODEL_VERSION_4, + }, + }, }, mappings: { dynamic: false, diff --git a/src/plugins/telemetry/schema/oss_plugins.json b/src/plugins/telemetry/schema/oss_plugins.json index 673361881b2ff..4b26657fc9339 100644 --- a/src/plugins/telemetry/schema/oss_plugins.json +++ b/src/plugins/telemetry/schema/oss_plugins.json @@ -10203,6 +10203,12 @@ "description": "Non-default value of setting." } }, + "observability:aiAssistantSearchConnectorIndexPattern": { + "type": "text", + "_meta": { + "description": "Non-default value of setting." + } + }, "observability:logsExplorer:allowedDataViews": { "type": "array", "items": { diff --git a/src/plugins/ui_actions/public/tests/test_samples/hello_world_action.tsx b/src/plugins/ui_actions/public/tests/test_samples/hello_world_action.tsx index 8df43b51a020c..d828a41d7b2ec 100644 --- a/src/plugins/ui_actions/public/tests/test_samples/hello_world_action.tsx +++ b/src/plugins/ui_actions/public/tests/test_samples/hello_world_action.tsx @@ -10,30 +10,37 @@ import React from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiBadge, EuiFlyoutBody } from '@elastic/eui'; import { CoreStart } from '@kbn/core/public'; import { toMountPoint } from '@kbn/react-kibana-mount'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import { ActionDefinition } from '../../actions'; -const MenuItem: React.FC = () => { - return ( - - Hello world! - - {'secret'} - - - ); +type StartServices = Pick; + +const getMenuItem = (core: StartServices) => { + return () => { + return ( + + + Hello world! + + {'secret'} + + + + ); + }; }; export const ACTION_HELLO_WORLD = 'ACTION_HELLO_WORLD'; export function createHelloWorldAction( - coreStart: Pick + coreStart: StartServices & Pick ): ActionDefinition { const { overlays, ...startServices } = coreStart; return { id: ACTION_HELLO_WORLD, type: ACTION_HELLO_WORLD, getIconType: () => 'lock', - MenuItem, + MenuItem: getMenuItem(startServices), execute: async () => { overlays.openFlyout( toMountPoint( diff --git a/src/plugins/vis_type_markdown/public/markdown_renderer.tsx b/src/plugins/vis_type_markdown/public/markdown_renderer.tsx index 38805bd5ce697..e733290f5815f 100644 --- a/src/plugins/vis_type_markdown/public/markdown_renderer.tsx +++ b/src/plugins/vis_type_markdown/public/markdown_renderer.tsx @@ -8,27 +8,43 @@ import React, { lazy } from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; + import { VisualizationContainer } from '@kbn/visualizations-plugin/public'; import { ExpressionRenderDefinition } from '@kbn/expressions-plugin/common/expression_renderers'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; +import { StartServicesAccessor } from '@kbn/core-lifecycle-browser'; import { MarkdownVisRenderValue } from './markdown_fn'; +/** @internal **/ +export interface MarkdownVisRendererDependencies { + getStartDeps: StartServicesAccessor; +} + // @ts-ignore const MarkdownVisComponent = lazy(() => import('./markdown_vis_controller')); -export const markdownVisRenderer: ExpressionRenderDefinition = { +export const getMarkdownVisRenderer: ({ + getStartDeps, +}: MarkdownVisRendererDependencies) => ExpressionRenderDefinition = ({ + getStartDeps, +}) => ({ name: 'markdown_vis', displayName: 'markdown visualization', reuseDomNode: true, render: async (domNode, { visParams }, handlers) => { + const [core] = await getStartDeps(); + handlers.onDestroy(() => { unmountComponentAtNode(domNode); }); render( - - - , + + + + + , domNode ); }, -}; +}); diff --git a/src/plugins/vis_type_markdown/public/plugin.ts b/src/plugins/vis_type_markdown/public/plugin.ts index 97848aab8afc7..66f46ce3bdbc0 100644 --- a/src/plugins/vis_type_markdown/public/plugin.ts +++ b/src/plugins/vis_type_markdown/public/plugin.ts @@ -13,7 +13,7 @@ import { VisualizationsSetup } from '@kbn/visualizations-plugin/public'; import { markdownVisDefinition } from './markdown_vis'; import { createMarkdownVisFn } from './markdown_fn'; import { ConfigSchema } from '../config'; -import { markdownVisRenderer } from './markdown_renderer'; +import { getMarkdownVisRenderer } from './markdown_renderer'; /** @internal */ export interface MarkdownPluginSetupDependencies { @@ -31,7 +31,7 @@ export class MarkdownPlugin implements Plugin { public setup(core: CoreSetup, { expressions, visualizations }: MarkdownPluginSetupDependencies) { visualizations.createBaseVisualization(markdownVisDefinition); - expressions.registerRenderer(markdownVisRenderer); + expressions.registerRenderer(getMarkdownVisRenderer({ getStartDeps: core.getStartServices })); expressions.registerFunction(createMarkdownVisFn); } diff --git a/src/plugins/vis_type_markdown/tsconfig.json b/src/plugins/vis_type_markdown/tsconfig.json index 5b9639787e12c..dbe601fad3f35 100644 --- a/src/plugins/vis_type_markdown/tsconfig.json +++ b/src/plugins/vis_type_markdown/tsconfig.json @@ -17,6 +17,8 @@ "@kbn/i18n-react", "@kbn/config-schema", "@kbn/kibana-react-plugin", + "@kbn/react-kibana-context-render", + "@kbn/core-lifecycle-browser", ], "exclude": [ "target/**/*", diff --git a/src/plugins/vis_types/timelion/public/timelion_vis_renderer.tsx b/src/plugins/vis_types/timelion/public/timelion_vis_renderer.tsx index a6fdbd998dc80..3d44d3b77c4c7 100644 --- a/src/plugins/vis_types/timelion/public/timelion_vis_renderer.tsx +++ b/src/plugins/vis_types/timelion/public/timelion_vis_renderer.tsx @@ -85,12 +85,12 @@ export const getTimelionVisRenderer: ( }; render( - - + + {seriesList && ( )} - - , + + , + domNode ); }, diff --git a/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx b/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx index be006bd1dd438..ad1678e4168ce 100644 --- a/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx +++ b/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx @@ -356,7 +356,13 @@ export class VisualizeEmbeddable } if (this.warningDomNode) { - render(, this.warningDomNode); + const { core } = this.deps.start(); + render( + + + , + this.warningDomNode + ); } } diff --git a/test/examples/config.js b/test/examples/config.js index 77d73642afd1c..dd8b49753dba5 100644 --- a/test/examples/config.js +++ b/test/examples/config.js @@ -31,6 +31,7 @@ export default async function ({ readConfigFile }) { require.resolve('./unified_field_list_examples'), require.resolve('./discover_customization_examples'), require.resolve('./error_boundary'), + require.resolve('./response_stream'), ], services: { ...functionalConfig.get('services'), diff --git a/test/examples/response_stream/index.ts b/test/examples/response_stream/index.ts index b918de669819b..2f13bf2f9f70c 100644 --- a/test/examples/response_stream/index.ts +++ b/test/examples/response_stream/index.ts @@ -10,7 +10,17 @@ import { FtrProviderContext } from '../../functional/ftr_provider_context'; // eslint-disable-next-line import/no-default-export export default function ({ getService, getPageObjects, loadTestFile }: FtrProviderContext) { - describe('response stream', function () { + const browser = getService('browser'); + const PageObjects = getPageObjects(['common', 'header']); + + describe('response-stream', function () { + before(async () => { + await browser.setWindowSize(1300, 900); + await PageObjects.common.navigateToApp('response-stream', { insertTimestamp: false }); + }); + + loadTestFile(require.resolve('./string_stream')); loadTestFile(require.resolve('./reducer_stream')); + loadTestFile(require.resolve('./redux_stream')); }); } diff --git a/test/examples/response_stream/reducer_stream.ts b/test/examples/response_stream/reducer_stream.ts index 001fea1a144c8..4e9c0f9a7af09 100644 --- a/test/examples/response_stream/reducer_stream.ts +++ b/test/examples/response_stream/reducer_stream.ts @@ -6,84 +6,47 @@ * Side Public License, v 1. */ -import fetch from 'node-fetch'; -import { format as formatUrl } from 'url'; - import expect from '@kbn/expect'; - import { FtrProviderContext } from '../../functional/ftr_provider_context'; -import { parseStream } from './parse_stream'; - // eslint-disable-next-line import/no-default-export -export default ({ getService }: FtrProviderContext) => { - const supertest = getService('supertest'); - const config = getService('config'); - const kibanaServerUrl = formatUrl(config.get('servers.kibana')); - - describe('POST /internal/response_stream/reducer_stream', () => { - it('should return full data without streaming', async () => { - const resp = await supertest - .post('/internal/response_stream/reducer_stream') - .set('kbn-xsrf', 'kibana') - .send({ - timeout: 1, - }) - .expect(200); - - expect(Buffer.isBuffer(resp.body)).to.be(true); - - const chunks: string[] = resp.body.toString().split('\n'); - - expect(chunks.length).to.be(201); - - const lastChunk = chunks.pop(); - expect(lastChunk).to.be(''); - - let data: any[] = []; +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const testSubjects = getService('testSubjects'); + const retry = getService('retry'); + + describe('useReducer stream example', () => { + it('navigates to the example', async () => { + await testSubjects.click('ndjson-usereducer-stream'); + + await retry.try(async () => { + expect(await testSubjects.getVisibleText('responseStreamPageTitle')).to.be( + 'NDJSON useReducer stream' + ); + expect(await testSubjects.getVisibleText('responseStreamProgressBadge')).to.be('0%'); + expect(await testSubjects.getVisibleText('responseStreamStatusMessage')).to.be( + 'Development did not start yet.' + ); + }); + }); - expect(() => { - data = chunks.map((c) => JSON.parse(c)); - }).not.to.throwError(); + it('starts the stream', async () => { + await testSubjects.click('responseStreamStartButton'); - data.forEach((d) => { - expect(typeof d.type).to.be('string'); + await retry.try(async () => { + expect(await testSubjects.getVisibleText('responseStreamProgressBadge')).not.to.be('0%'); + expect(await testSubjects.getVisibleText('responseStreamStatusMessage')).to.be( + 'Development is ongoing, the hype is real!' + ); }); - - const progressData = data.filter((d) => d.type === 'update_progress'); - expect(progressData.length).to.be(100); - expect(progressData[0].payload).to.be(1); - expect(progressData[progressData.length - 1].payload).to.be(100); }); - it('should return data in chunks with streaming', async () => { - const response = await fetch(`${kibanaServerUrl}/internal/response_stream/reducer_stream`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'kbn-xsrf': 'stream', - }, - body: JSON.stringify({ timeout: 1 }), + it('finishes the stream', async () => { + await retry.tryForTime(60000, async () => { + expect(await testSubjects.getVisibleText('responseStreamProgressBadge')).to.be('100%'); + expect(await testSubjects.getVisibleText('responseStreamStatusMessage')).to.be( + 'Development completed, the release got out the door!' + ); }); - - const stream = response.body; - - expect(stream).not.to.be(null); - - if (stream !== null) { - const progressData: any[] = []; - - for await (const action of parseStream(stream)) { - expect(action.type).not.to.be('error'); - if (action.type === 'update_progress') { - progressData.push(action); - } - } - - expect(progressData.length).to.be(100); - expect(progressData[0].payload).to.be(1); - expect(progressData[progressData.length - 1].payload).to.be(100); - } }); }); -}; +} diff --git a/test/examples/response_stream/redux_stream.ts b/test/examples/response_stream/redux_stream.ts new file mode 100644 index 0000000000000..6a9e73d1d35a5 --- /dev/null +++ b/test/examples/response_stream/redux_stream.ts @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../functional/ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const testSubjects = getService('testSubjects'); + const retry = getService('retry'); + + describe('redux stream example', () => { + it('navigates to the example', async () => { + await testSubjects.click('ndjson-redux-toolkit-stream'); + + await retry.try(async () => { + expect(await testSubjects.getVisibleText('responseStreamPageTitle')).to.be( + 'NDJSON Redux Toolkit stream' + ); + expect(await testSubjects.getVisibleText('responseStreamProgressBadge')).to.be('0%'); + expect(await testSubjects.getVisibleText('responseStreamStatusMessage')).to.be( + 'Development did not start yet.' + ); + }); + }); + + it('starts the stream', async () => { + await testSubjects.click('responseStreamStartButton'); + + await retry.try(async () => { + expect(await testSubjects.getVisibleText('responseStreamProgressBadge')).not.to.be('0%'); + expect(await testSubjects.getVisibleText('responseStreamStatusMessage')).to.be( + 'Development is ongoing, the hype is real!' + ); + }); + }); + + it('finishes the stream', async () => { + await retry.tryForTime(60000, async () => { + expect(await testSubjects.getVisibleText('responseStreamProgressBadge')).to.be('100%'); + expect(await testSubjects.getVisibleText('responseStreamStatusMessage')).to.be( + 'Development completed, the release got out the door!' + ); + }); + }); + }); +} diff --git a/test/examples/response_stream/string_stream.ts b/test/examples/response_stream/string_stream.ts new file mode 100644 index 0000000000000..d522b8f5f2484 --- /dev/null +++ b/test/examples/response_stream/string_stream.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../functional/ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const testSubjects = getService('testSubjects'); + const retry = getService('retry'); + + describe('string stream example', () => { + it('navigates to the example', async () => { + await testSubjects.click('simple-string-stream'); + + await retry.try(async () => { + expect(await testSubjects.getVisibleText('responseStreamPageTitle')).to.be( + 'Simple string stream' + ); + expect(await testSubjects.exists('responseStreamStartButton')).to.be(true); + expect(await testSubjects.getVisibleText('responseStreamString')).to.be(''); + }); + }); + + it('starts the stream', async () => { + await testSubjects.click('responseStreamStartButton'); + + await retry.try(async () => { + expect(await testSubjects.getVisibleText('responseStreamString')).not.to.be(''); + }); + }); + + it('finishes the stream', async () => { + await retry.tryForTime(60000, async () => { + expect(await testSubjects.getVisibleText('responseStreamString')).to.be( + 'Elasticsearch is a search engine based on the Lucene library. It provides a distributed, multitenant-capable full-text search engine with an HTTP web interface and schema-free JSON documents. Elasticsearch is developed in Java and is dual-licensed under the source-available Server Side Public License and the Elastic license, while other parts fall under the proprietary (source-available) Elastic License. Official clients are available in Java, .NET (C#), PHP, Python, Apache Groovy, Ruby and many other languages. According to the DB-Engines ranking, Elasticsearch is the most popular enterprise search engine.' + ); + }); + }); + }); +} diff --git a/test/functional/apps/dashboard/group3/dashboard_state.ts b/test/functional/apps/dashboard/group3/dashboard_state.ts index d5d522a738481..423adf781835c 100644 --- a/test/functional/apps/dashboard/group3/dashboard_state.ts +++ b/test/functional/apps/dashboard/group3/dashboard_state.ts @@ -185,7 +185,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.dashboard.waitForRenderComplete(); }; - describe('Directly modifying url updates dashboard state', () => { + // FLAKY: https://github.com/elastic/kibana/issues/139762 + describe.skip('Directly modifying url updates dashboard state', () => { before(async () => { await PageObjects.dashboard.gotoDashboardLandingPage(); await PageObjects.dashboard.clickNewDashboard(); diff --git a/test/functional/apps/discover/group4/_esql_view.ts b/test/functional/apps/discover/group4/_esql_view.ts index 17c2e9542d774..a1cecdbc36d4c 100644 --- a/test/functional/apps/discover/group4/_esql_view.ts +++ b/test/functional/apps/discover/group4/_esql_view.ts @@ -261,16 +261,28 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { beforeEach(async () => { await PageObjects.common.navigateToApp('discover'); await PageObjects.timePicker.setDefaultAbsoluteRange(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); }); it('shows Discover and Lens requests in Inspector', async () => { await PageObjects.discover.selectTextBaseLang(); await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.discover.waitUntilSearchingHasFinished(); - await inspector.open(); - const requestNames = await inspector.getRequestNames(); - expect(requestNames).to.contain('Table'); - expect(requestNames).to.contain('Visualization'); + let retries = 0; + await retry.try(async () => { + if (retries > 0) { + await inspector.close(); + await testSubjects.click('querySubmitButton'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + } + await inspector.open(); + retries = retries + 1; + const requestNames = await inspector.getRequestNames(); + expect(requestNames).to.contain('Table'); + expect(requestNames).to.contain('Visualization'); + }); }); }); diff --git a/test/functional/apps/discover/group6/_view_mode_toggle.ts b/test/functional/apps/discover/group6/_view_mode_toggle.ts index eada1ec26f7aa..ba964c7532d70 100644 --- a/test/functional/apps/discover/group6/_view_mode_toggle.ts +++ b/test/functional/apps/discover/group6/_view_mode_toggle.ts @@ -88,6 +88,14 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await testSubjects.missingOrFail('discoverErrorCalloutTitle'); }); + it('should not show Patterns tab (basic license)', async () => { + await testSubjects.missingOrFail('dscViewModePatternAnalysisButton'); + await retry.try(async () => { + const documentTab = await testSubjects.find('dscViewModeDocumentButton'); + expect(await documentTab.getAttribute('aria-selected')).to.be('true'); + }); + }); + it('should show Field Statistics tab', async () => { await testSubjects.click('dscViewModeFieldStatsButton'); diff --git a/test/functional/services/data_grid.ts b/test/functional/services/data_grid.ts index a6c91d91a8961..18282442696ff 100644 --- a/test/functional/services/data_grid.ts +++ b/test/functional/services/data_grid.ts @@ -376,12 +376,12 @@ export class DataGridService extends FtrService { await this.testSubjects.click('dataGridDisplaySelectorButton'); } - public async getCurrentRowHeightValue() { + public async getCurrentRowHeightValue(scope: 'row' | 'header' = 'row') { const buttonGroup = await this.testSubjects.find( - 'unifiedDataTableRowHeightSettings_rowHeightButtonGroup' + `unifiedDataTable${scope === 'header' ? 'Header' : ''}RowHeightSettings_rowHeightButtonGroup` ); let value = ''; - await this.retry.waitFor('row height value not to be empty', async () => { + await this.retry.waitFor(`${scope} height value not to be empty`, async () => { // to prevent flakiness const selectedButton = await buttonGroup.findByCssSelector( '.euiButtonGroupButton-isSelected' @@ -401,12 +401,7 @@ export class DataGridService extends FtrService { } public async getCurrentHeaderRowHeightValue() { - const buttonGroup = await this.testSubjects.find( - 'unifiedDataTableHeaderRowHeightSettings_rowHeightButtonGroup' - ); - return ( - await buttonGroup.findByCssSelector('.euiButtonGroupButton-isSelected') - ).getVisibleText(); + return await this.getCurrentRowHeightValue('header'); } public async changeHeaderRowHeightValue(newValue: string) { diff --git a/test/plugin_functional/plugins/kbn_tp_custom_visualizations/public/plugin.ts b/test/plugin_functional/plugins/kbn_tp_custom_visualizations/public/plugin.ts index a81cb2d827267..0b9d85fe57918 100644 --- a/test/plugin_functional/plugins/kbn_tp_custom_visualizations/public/plugin.ts +++ b/test/plugin_functional/plugins/kbn_tp_custom_visualizations/public/plugin.ts @@ -12,7 +12,7 @@ import { Plugin as ExpressionsPlugin } from '@kbn/expressions-plugin/public'; import { SelfChangingEditor } from './self_changing_vis/self_changing_editor'; import { selfChangingVisFn, SelfChangingVisParams } from './self_changing_vis_fn'; -import { selfChangingVisRenderer } from './self_changing_vis_renderer'; +import { getSelfChangingVisRenderer } from './self_changing_vis_renderer'; import { toExpressionAst } from './to_ast'; export interface SetupDependencies { @@ -32,7 +32,7 @@ export class CustomVisualizationsPublicPlugin /** * Register a renderer for your visualization */ - expressions.registerRenderer(selfChangingVisRenderer); + expressions.registerRenderer(getSelfChangingVisRenderer(core)); /** * Create the visualization type with definition diff --git a/test/plugin_functional/plugins/kbn_tp_custom_visualizations/public/self_changing_vis_renderer.tsx b/test/plugin_functional/plugins/kbn_tp_custom_visualizations/public/self_changing_vis_renderer.tsx index 99db3537e5d2d..3f776f411a984 100644 --- a/test/plugin_functional/plugins/kbn_tp_custom_visualizations/public/self_changing_vis_renderer.tsx +++ b/test/plugin_functional/plugins/kbn_tp_custom_visualizations/public/self_changing_vis_renderer.tsx @@ -9,18 +9,30 @@ import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import { ExpressionRenderDefinition } from '@kbn/expressions-plugin/common'; +import { CoreSetup } from '@kbn/core-lifecycle-browser'; import { SelfChangingComponent } from './self_changing_vis/self_changing_components'; import { SelfChangingVisRenderValue } from './self_changing_vis_fn'; -export const selfChangingVisRenderer: ExpressionRenderDefinition = { - name: 'self_changing_vis', - reuseDomNode: true, - render: (domNode, { visParams }, handlers) => { - handlers.onDestroy(() => { - unmountComponentAtNode(domNode); - }); +export const getSelfChangingVisRenderer = (core: CoreSetup) => { + const selfChangingVisRenderer: ExpressionRenderDefinition = { + name: 'self_changing_vis', + reuseDomNode: true, + render: async (domNode, { visParams }, handlers) => { + const [coreSetup] = await core.getStartServices(); + handlers.onDestroy(() => { + unmountComponentAtNode(domNode); + }); - render(, domNode); - }, + render( + + + , + domNode + ); + }, + }; + + return selfChangingVisRenderer; }; diff --git a/test/plugin_functional/plugins/kbn_tp_custom_visualizations/tsconfig.json b/test/plugin_functional/plugins/kbn_tp_custom_visualizations/tsconfig.json index 0b75f43b4b7f7..d6a9035ffb765 100644 --- a/test/plugin_functional/plugins/kbn_tp_custom_visualizations/tsconfig.json +++ b/test/plugin_functional/plugins/kbn_tp_custom_visualizations/tsconfig.json @@ -17,5 +17,7 @@ "@kbn/data-plugin", "@kbn/visualizations-plugin", "@kbn/expressions-plugin", + "@kbn/core-lifecycle-browser", + "@kbn/react-kibana-context-render", ] } diff --git a/tsconfig.base.json b/tsconfig.base.json index dd82d55b1b0ad..23c8774271af9 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1028,6 +1028,8 @@ "@kbn/kibana-utils-plugin/*": ["src/plugins/kibana_utils/*"], "@kbn/kubernetes-security-plugin": ["x-pack/plugins/kubernetes_security"], "@kbn/kubernetes-security-plugin/*": ["x-pack/plugins/kubernetes_security/*"], + "@kbn/langchain": ["x-pack/packages/kbn-langchain"], + "@kbn/langchain/*": ["x-pack/packages/kbn-langchain/*"], "@kbn/language-documentation-popover": ["packages/kbn-language-documentation-popover"], "@kbn/language-documentation-popover/*": ["packages/kbn-language-documentation-popover/*"], "@kbn/lens-config-builder-example-plugin": ["x-pack/examples/lens_config_builder_example"], @@ -1628,8 +1630,6 @@ "@kbn/slo-schema/*": ["x-pack/packages/kbn-slo-schema/*"], "@kbn/snapshot-restore-plugin": ["x-pack/plugins/snapshot_restore"], "@kbn/snapshot-restore-plugin/*": ["x-pack/plugins/snapshot_restore/*"], - "@kbn/solution-nav-es": ["packages/solution-nav/es"], - "@kbn/solution-nav-es/*": ["packages/solution-nav/es/*"], "@kbn/solution-nav-oblt": ["packages/solution-nav/oblt"], "@kbn/solution-nav-oblt/*": ["packages/solution-nav/oblt/*"], "@kbn/some-dev-log": ["packages/kbn-some-dev-log"], diff --git a/x-pack/examples/embedded_lens_example/public/mount.tsx b/x-pack/examples/embedded_lens_example/public/mount.tsx index 62786e9918de6..6ff43709d3f89 100644 --- a/x-pack/examples/embedded_lens_example/public/mount.tsx +++ b/x-pack/examples/embedded_lens_example/public/mount.tsx @@ -10,6 +10,7 @@ import { render, unmountComponentAtNode } from 'react-dom'; import { EuiCallOut } from '@elastic/eui'; import type { CoreSetup, AppMountParameters } from '@kbn/core/public'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import type { StartDependencies } from './plugin'; export const mount = @@ -21,10 +22,11 @@ export const mount = const defaultDataView = await plugins.data.indexPatterns.getDefault(); const { formula } = await plugins.lens.stateHelperApi(); - const i18nCore = core.i18n; + const { analytics, i18n, theme } = core; + const startServices = { analytics, i18n, theme }; const reactElement = ( - + {defaultDataView && defaultDataView.isTimeBased() ? ( ) : ( @@ -36,7 +38,7 @@ export const mount =

This demo only works if your default index pattern is set and time based

)} -
+ ); render(reactElement, element); diff --git a/x-pack/examples/embedded_lens_example/tsconfig.json b/x-pack/examples/embedded_lens_example/tsconfig.json index ea5b99db315de..d155e7ec22bd1 100644 --- a/x-pack/examples/embedded_lens_example/tsconfig.json +++ b/x-pack/examples/embedded_lens_example/tsconfig.json @@ -21,5 +21,6 @@ "@kbn/developer-examples-plugin", "@kbn/data-views-plugin", "@kbn/ui-actions-plugin", + "@kbn/react-kibana-context-render", ] } diff --git a/x-pack/examples/screenshotting_example/public/app/app.tsx b/x-pack/examples/screenshotting_example/public/app/app.tsx index 4ca15f7f8c196..50c2e7d786309 100644 --- a/x-pack/examples/screenshotting_example/public/app/app.tsx +++ b/x-pack/examples/screenshotting_example/public/app/app.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useCallback, useContext, useState } from 'react'; +import React, { useCallback, useState } from 'react'; import { EuiButton, EuiCallOut, @@ -24,11 +24,12 @@ import { EuiTextArea, EuiTitle, } from '@elastic/eui'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import { API_ENDPOINT, ScreenshottingExpressionResponse } from '../../common'; -import { HttpContext } from './http_context'; +import { useAppContext } from './http_context'; export function App() { - const http = useContext(HttpContext); + const { http, ...startServices } = useAppContext(); const [expression, setExpression] = useState(); const [loading, setLoading] = useState(false); const [response, setResponse] = useState(); @@ -37,7 +38,7 @@ export function App() { try { setLoading(true); setResponse( - await http?.get(API_ENDPOINT, { + await http.get(API_ENDPOINT, { query: { expression }, }) ); @@ -50,85 +51,87 @@ export function App() { }, []); return ( - - - - - -

Screenshotting Demo

-
-
-
- - -

This example captures a screenshot of an expression provided below.

-
- - - - - Run - - {!!response && } - {response?.errors && ( - <> - -

{response.errors.join('\n')}

-
- - - )} - - - {response?.image && ( - - )} - - - {response?.metrics && ( - <> - + + + + + +

Screenshotting Demo

+
+
+
+ + +

This example captures a screenshot of an expression provided below.

+
+ + + + + Run + + {!!response && } + {response?.errors && ( + <> + +

{response.errors.join('\n')}

+
+ + + )} + + + {response?.image && ( + - - - - )} - - -
-
-
+ )} +
+ + {response?.metrics && ( + <> + + + + + )} + +
+
+
+
+ ); } diff --git a/x-pack/examples/screenshotting_example/public/app/http_context.ts b/x-pack/examples/screenshotting_example/public/app/http_context.ts index e33a7bee5c6ce..7bc0b2b4f2870 100644 --- a/x-pack/examples/screenshotting_example/public/app/http_context.ts +++ b/x-pack/examples/screenshotting_example/public/app/http_context.ts @@ -5,7 +5,29 @@ * 2.0. */ -import { createContext } from 'react'; -import type { HttpStart } from '@kbn/core/public'; +import { createContext, useContext } from 'react'; +import type { + AnalyticsServiceStart, + HttpStart, + I18nStart, + ThemeServiceStart, +} from '@kbn/core/public'; -export const HttpContext = createContext(undefined); +export interface StartServices { + http: HttpStart; + analytics: Pick; + i18n: I18nStart; + theme: Pick; +} + +export const AppContext = createContext(undefined); + +export const useAppContext = () => { + const context = useContext(AppContext); + + if (!context) { + throw new Error('App Context Error!'); + } + + return context; +}; diff --git a/x-pack/examples/screenshotting_example/public/plugin.tsx b/x-pack/examples/screenshotting_example/public/plugin.tsx index a36a2c478799e..6dd07b992b1c3 100644 --- a/x-pack/examples/screenshotting_example/public/plugin.tsx +++ b/x-pack/examples/screenshotting_example/public/plugin.tsx @@ -10,7 +10,7 @@ import ReactDOM from 'react-dom'; import type { AppMountParameters, CoreSetup, Plugin } from '@kbn/core/public'; import type { DeveloperExamplesSetup } from '@kbn/developer-examples-plugin/public'; -import { App, HttpContext } from './app'; +import { App, AppContext } from './app'; interface SetupDeps { developerExamples: DeveloperExamplesSetup; @@ -26,12 +26,13 @@ export class ScreenshottingExamplePlugin implements Plugin { title: APPLICATION_NAME, visibleIn: [], mount: async ({ element }: AppMountParameters) => { - const [{ http }] = await getStartServices(); + const [{ http, analytics, i18n, theme }] = await getStartServices(); + const startServices = { analytics, http, i18n, theme }; ReactDOM.render( - + - , + , element ); return () => ReactDOM.unmountComponentAtNode(element); diff --git a/x-pack/examples/screenshotting_example/tsconfig.json b/x-pack/examples/screenshotting_example/tsconfig.json index 3c1351f817c11..6187b2b5ceea0 100644 --- a/x-pack/examples/screenshotting_example/tsconfig.json +++ b/x-pack/examples/screenshotting_example/tsconfig.json @@ -19,5 +19,6 @@ "@kbn/developer-examples-plugin", "@kbn/screenshotting-plugin", "@kbn/config-schema", + "@kbn/react-kibana-context-render", ] } diff --git a/x-pack/examples/triggers_actions_ui_example/public/application.tsx b/x-pack/examples/triggers_actions_ui_example/public/application.tsx index 2da1524f73c37..d36d4a91ddd87 100644 --- a/x-pack/examples/triggers_actions_ui_example/public/application.tsx +++ b/x-pack/examples/triggers_actions_ui_example/public/application.tsx @@ -12,6 +12,7 @@ import { Route } from '@kbn/shared-ux-router'; import { EuiPage, EuiTitle, EuiText, EuiSpacer } from '@elastic/eui'; import { AppMountParameters, CoreStart } from '@kbn/core/public'; import { TriggersAndActionsUIPublicPluginStart } from '@kbn/triggers-actions-ui-plugin/public'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { DataPublicPluginStart } from '@kbn/data-plugin/public'; import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; @@ -157,23 +158,25 @@ export const renderApp = ( const { triggersActionsUi } = deps; const { ruleTypeRegistry, actionTypeRegistry } = triggersActionsUi; ReactDOM.render( - - - - - , + + + + + + + , element ); diff --git a/x-pack/examples/triggers_actions_ui_example/tsconfig.json b/x-pack/examples/triggers_actions_ui_example/tsconfig.json index 64e9254eadc95..193feffd2d5ee 100644 --- a/x-pack/examples/triggers_actions_ui_example/tsconfig.json +++ b/x-pack/examples/triggers_actions_ui_example/tsconfig.json @@ -26,5 +26,6 @@ "@kbn/i18n", "@kbn/actions-plugin", "@kbn/config-schema", + "@kbn/react-kibana-context-render", ] } diff --git a/x-pack/packages/kbn-elastic-assistant-common/constants.ts b/x-pack/packages/kbn-elastic-assistant-common/constants.ts index 67a20011dffd9..f30cb053d4ce1 100755 --- a/x-pack/packages/kbn-elastic-assistant-common/constants.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/constants.ts @@ -8,18 +8,24 @@ export const ELASTIC_AI_ASSISTANT_INTERNAL_API_VERSION = '1'; export const ELASTIC_AI_ASSISTANT_URL = '/api/elastic_assistant'; +export const ELASTIC_AI_ASSISTANT_INTERNAL_URL = '/internal/elastic_assistant'; -export const ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL = `${ELASTIC_AI_ASSISTANT_URL}/current_user/conversations`; +export const ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL = `${ELASTIC_AI_ASSISTANT_INTERNAL_URL}/current_user/conversations`; export const ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL_BY_ID = `${ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL}/{id}`; export const ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL_BY_ID_MESSAGES = `${ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL_BY_ID}/messages`; export const ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL_BULK_ACTION = `${ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL}/_bulk_action`; export const ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL_FIND = `${ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL}/_find`; -export const ELASTIC_AI_ASSISTANT_PROMPTS_URL = `${ELASTIC_AI_ASSISTANT_URL}/prompts`; +export const ELASTIC_AI_ASSISTANT_PROMPTS_URL = `${ELASTIC_AI_ASSISTANT_INTERNAL_URL}/prompts`; export const ELASTIC_AI_ASSISTANT_PROMPTS_URL_BULK_ACTION = `${ELASTIC_AI_ASSISTANT_PROMPTS_URL}/_bulk_action`; export const ELASTIC_AI_ASSISTANT_PROMPTS_URL_FIND = `${ELASTIC_AI_ASSISTANT_PROMPTS_URL}/_find`; -export const ELASTIC_AI_ASSISTANT_ANONYMIZATION_FIELDS_URL = `${ELASTIC_AI_ASSISTANT_URL}/anonymization_fields`; +export const ELASTIC_AI_ASSISTANT_ANONYMIZATION_FIELDS_URL = `${ELASTIC_AI_ASSISTANT_INTERNAL_URL}/anonymization_fields`; export const ELASTIC_AI_ASSISTANT_ANONYMIZATION_FIELDS_URL_BULK_ACTION = `${ELASTIC_AI_ASSISTANT_ANONYMIZATION_FIELDS_URL}/_bulk_action`; export const ELASTIC_AI_ASSISTANT_ANONYMIZATION_FIELDS_URL_FIND = `${ELASTIC_AI_ASSISTANT_ANONYMIZATION_FIELDS_URL}/_find`; + +// TODO: Update existing 'status' endpoint to take resource as query param as to not conflict with 'entries' +export const ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_URL = `${ELASTIC_AI_ASSISTANT_INTERNAL_URL}/knowledge_base/{resource?}`; +export const ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_ENTRIES_URL = `${ELASTIC_AI_ASSISTANT_URL}/knowledge_base/entries`; +export const ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_ENTRIES_URL_BULK_ACTION = `${ELASTIC_AI_ASSISTANT_URL}/knowledge_base/_bulk_action`; diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/capabilities/index.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/capabilities/index.ts index 2a6cce1adbdbb..9c734cc4b3c13 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/capabilities/index.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/capabilities/index.ts @@ -14,5 +14,6 @@ export type AssistantFeatures = { [K in keyof typeof defaultAssistantFeatures]: * Default features available to the elastic assistant */ export const defaultAssistantFeatures = Object.freeze({ + assistantKnowledgeBaseByDefault: false, assistantModelEvaluation: false, }); 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 be9ed538cda7f..1b855650ddcfc 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 @@ -16,7 +16,8 @@ import { z } from 'zod'; * version: 1 */ -import { UUID, Replacements } from '../conversations/common_attributes.gen'; +import { NonEmptyString } from '../common_attributes.gen'; +import { Replacements } from '../conversations/common_attributes.gen'; export type ExecuteConnectorRequestParams = z.infer; export const ExecuteConnectorRequestParams = z.object({ @@ -29,7 +30,7 @@ export type ExecuteConnectorRequestParamsInput = z.input; export const ExecuteConnectorRequestBody = z.object({ - conversationId: UUID.optional(), + conversationId: NonEmptyString.optional(), message: z.string().optional(), model: z.string().optional(), subAction: z.enum(['invokeAI', 'invokeStream']), 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 d8bb1396746ed..9ea3c4107c7d1 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 @@ -31,7 +31,7 @@ paths: - subAction properties: conversationId: - $ref: '../conversations/common_attributes.schema.yaml#/components/schemas/UUID' + $ref: '../common_attributes.schema.yaml#/components/schemas/NonEmptyString' message: type: string model: diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/anonymization_fields/bulk_crud_anonymization_fields_route.gen.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/anonymization_fields/bulk_crud_anonymization_fields_route.gen.ts index bc2cb93bb30c3..1fe37666b93e7 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/anonymization_fields/bulk_crud_anonymization_fields_route.gen.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/anonymization_fields/bulk_crud_anonymization_fields_route.gen.ts @@ -13,10 +13,10 @@ import { z } from 'zod'; * * info: * title: Bulk Actions API endpoint - * version: 2023-10-31 + * version: 1 */ -import { UUID, NonEmptyString } from '../conversations/common_attributes.gen'; +import { NonEmptyString } from '../common_attributes.gen'; export type BulkActionSkipReason = z.infer; export const BulkActionSkipReason = z.literal('ANONYMIZATION_FIELD_NOT_MODIFIED'); @@ -44,7 +44,7 @@ export const NormalizedAnonymizationFieldError = z.object({ export type AnonymizationFieldResponse = z.infer; export const AnonymizationFieldResponse = z.object({ - id: UUID, + id: NonEmptyString, timestamp: NonEmptyString.optional(), field: z.string(), allowed: z.boolean().optional(), diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/anonymization_fields/bulk_crud_anonymization_fields_route.schema.yaml b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/anonymization_fields/bulk_crud_anonymization_fields_route.schema.yaml index e07e492b5fdbe..9e2623966f129 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/anonymization_fields/bulk_crud_anonymization_fields_route.schema.yaml +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/anonymization_fields/bulk_crud_anonymization_fields_route.schema.yaml @@ -1,9 +1,9 @@ openapi: 3.0.0 info: title: Bulk Actions API endpoint - version: '2023-10-31' + version: '1' paths: - /api/elastic_assistant/anonymization_fields/_bulk_action: + /internal/elastic_assistant/anonymization_fields/_bulk_action: post: operationId: PerformBulkAction x-codegen-enabled: true @@ -103,9 +103,9 @@ components: - field properties: id: - $ref: '../conversations/common_attributes.schema.yaml#/components/schemas/UUID' + $ref: '../common_attributes.schema.yaml#/components/schemas/NonEmptyString' 'timestamp': - $ref: '../conversations/common_attributes.schema.yaml#/components/schemas/NonEmptyString' + $ref: '../common_attributes.schema.yaml#/components/schemas/NonEmptyString' field: type: string allowed: @@ -232,4 +232,3 @@ components: type: boolean anonymized: type: boolean - \ No newline at end of file diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/anonymization_fields/find_anonymization_fields_route.gen.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/anonymization_fields/find_anonymization_fields_route.gen.ts index a0c83a6594fad..ce24ee0bb54e0 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/anonymization_fields/find_anonymization_fields_route.gen.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/anonymization_fields/find_anonymization_fields_route.gen.ts @@ -14,7 +14,7 @@ import { ArrayFromString } from '@kbn/zod-helpers'; * * info: * title: Find AnonymizationFields API endpoint - * version: 2023-10-31 + * version: 1 */ import { AnonymizationFieldResponse } from './bulk_crud_anonymization_fields_route.gen'; diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/anonymization_fields/find_anonymization_fields_route.schema.yaml b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/anonymization_fields/find_anonymization_fields_route.schema.yaml index 4861d267ce5c8..b9b2d1e9e2097 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/anonymization_fields/find_anonymization_fields_route.schema.yaml +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/anonymization_fields/find_anonymization_fields_route.schema.yaml @@ -1,9 +1,9 @@ openapi: 3.0.0 info: title: Find AnonymizationFields API endpoint - version: '2023-10-31' + version: '1' paths: - /api/elastic_assistant/anonymization_fields/_find: + /internal/elastic_assistant/anonymization_fields/_find: get: operationId: FindAnonymizationFields x-codegen-enabled: true diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/capabilities/get_capabilities_route.gen.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/capabilities/get_capabilities_route.gen.ts index 5d218afd48131..6c2ea102a501d 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/capabilities/get_capabilities_route.gen.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/capabilities/get_capabilities_route.gen.ts @@ -18,5 +18,6 @@ import { z } from 'zod'; export type GetCapabilitiesResponse = z.infer; export const GetCapabilitiesResponse = z.object({ + assistantKnowledgeBaseByDefault: z.boolean(), assistantModelEvaluation: z.boolean(), }); diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/capabilities/get_capabilities_route.schema.yaml b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/capabilities/get_capabilities_route.schema.yaml index 4664405cfef33..7461bdbc93237 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/capabilities/get_capabilities_route.schema.yaml +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/capabilities/get_capabilities_route.schema.yaml @@ -19,9 +19,12 @@ paths: schema: type: object properties: + assistantKnowledgeBaseByDefault: + type: boolean assistantModelEvaluation: type: boolean required: + - assistantKnowledgeBaseByDefault - assistantModelEvaluation '400': description: Generic Error diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.gen.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.gen.ts new file mode 100644 index 0000000000000..d98ee02af9ce4 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.gen.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { z } from 'zod'; + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Common Elastic AI Assistant Attributes + * version: not applicable + */ + +/** + * A string that is not empty and does not contain only whitespace + */ +export type NonEmptyString = z.infer; +export const NonEmptyString = z + .string() + .min(1) + .regex(/^(?! *$).+$/); + +/** + * A universally unique identifier + */ +export type UUID = z.infer; +export const UUID = z.string().uuid(); + +/** + * Could be any string, not necessarily a UUID + */ +export type User = z.infer; +export const User = z.object({ + /** + * User id + */ + id: z.string().optional(), + /** + * User name + */ + name: z.string().optional(), +}); diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.schema.yaml b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.schema.yaml new file mode 100644 index 0000000000000..5c580c52281ad --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/common_attributes.schema.yaml @@ -0,0 +1,30 @@ +openapi: 3.0.0 +info: + title: Common Elastic AI Assistant Attributes + version: 'not applicable' +paths: {} +components: + x-codegen-enabled: true + schemas: + NonEmptyString: + type: string + pattern: ^(?! *$).+$ + minLength: 1 + description: A string that is not empty and does not contain only whitespace + + UUID: + type: string + format: uuid + description: A universally unique identifier + + User: + type: object + description: Could be any string, not necessarily a UUID + properties: + id: + type: string + description: User id + name: + type: string + description: User name + diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/bulk_crud_conversations_route.gen.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/bulk_crud_conversations_route.gen.ts index bb401150bbee0..1acde90ccebb3 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/bulk_crud_conversations_route.gen.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/bulk_crud_conversations_route.gen.ts @@ -13,7 +13,7 @@ import { z } from 'zod'; * * info: * title: Bulk Actions API endpoint - * version: 2023-10-31 + * version: 1 */ import { diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/bulk_crud_conversations_route.schema.yaml b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/bulk_crud_conversations_route.schema.yaml index 790f4e5e85d5e..0768508205708 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/bulk_crud_conversations_route.schema.yaml +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/bulk_crud_conversations_route.schema.yaml @@ -1,9 +1,9 @@ openapi: 3.0.0 info: title: Bulk Actions API endpoint - version: '2023-10-31' + version: '1' paths: - /api/elastic_assistant/conversations/_bulk_action: + /internal/elastic_assistant/conversations/_bulk_action: post: operationId: PerformBulkAction x-codegen-enabled: true diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts index 808cf88fcec7c..a8637be38c146 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts @@ -16,35 +16,7 @@ import { z } from 'zod'; * version: not applicable */ -/** - * A string that is not empty and does not contain only whitespace - */ -export type NonEmptyString = z.infer; -export const NonEmptyString = z - .string() - .min(1) - .regex(/^(?! *$).+$/); - -/** - * A universally unique identifier - */ -export type UUID = z.infer; -export const UUID = z.string().uuid(); - -/** - * Could be any string, not necessarily a UUID - */ -export type User = z.infer; -export const User = z.object({ - /** - * User id. - */ - id: z.string().optional(), - /** - * User name. - */ - name: z.string().optional(), -}); +import { NonEmptyString, User } from '../common_attributes.gen'; /** * trace Data @@ -180,7 +152,7 @@ export const ConversationSummary = z.object({ export type ErrorSchema = z.infer; export const ErrorSchema = z .object({ - id: UUID.optional(), + id: NonEmptyString.optional(), error: z.object({ status_code: z.number().int().min(400), message: z.string(), @@ -190,7 +162,7 @@ export const ErrorSchema = z export type ConversationResponse = z.infer; export const ConversationResponse = z.object({ - id: z.union([UUID, NonEmptyString]), + id: NonEmptyString, /** * The conversation title. */ @@ -235,7 +207,7 @@ export const ConversationResponse = z.object({ export type ConversationUpdateProps = z.infer; export const ConversationUpdateProps = z.object({ - id: z.union([UUID, NonEmptyString]), + id: NonEmptyString, /** * The conversation title. */ diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.schema.yaml b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.schema.yaml index 3f2827b348004..49aaaa5663a1c 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.schema.yaml +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.schema.yaml @@ -6,27 +6,6 @@ paths: {} components: x-codegen-enabled: true schemas: - NonEmptyString: - type: string - pattern: ^(?! *$).+$ - minLength: 1 - description: A string that is not empty and does not contain only whitespace - - UUID: - type: string - format: uuid - description: A universally unique identifier - - User: - type: object - description: Could be any string, not necessarily a UUID - properties: - id: - type: string - description: User id. - name: - type: string - description: User name. TraceData: type: object @@ -97,7 +76,7 @@ components: $ref: '#/components/schemas/MessageRole' description: Message role. timestamp: - $ref: '#/components/schemas/NonEmptyString' + $ref: '../common_attributes.schema.yaml#/components/schemas/NonEmptyString' description: The timestamp message was sent or received. isError: type: boolean @@ -135,7 +114,7 @@ components: type: string description: Summary text of the conversation over time. timestamp: - $ref: '#/components/schemas/NonEmptyString' + $ref: '../common_attributes.schema.yaml#/components/schemas/NonEmptyString' description: The timestamp summary was updated. public: type: boolean @@ -151,7 +130,7 @@ components: additionalProperties: false properties: id: - $ref: '#/components/schemas/UUID' + $ref: '../common_attributes.schema.yaml#/components/schemas/NonEmptyString' error: type: object required: @@ -175,9 +154,7 @@ components: - category properties: id: - oneOf: - - $ref: '#/components/schemas/UUID' - - $ref: '#/components/schemas/NonEmptyString' + $ref: '../common_attributes.schema.yaml#/components/schemas/NonEmptyString' title: type: string description: The conversation title. @@ -187,7 +164,7 @@ components: summary: $ref: '#/components/schemas/ConversationSummary' 'timestamp': - $ref: '#/components/schemas/NonEmptyString' + $ref: '../common_attributes.schema.yaml#/components/schemas/NonEmptyString' updatedAt: description: The last time conversation was updated. type: string @@ -199,7 +176,7 @@ components: users: type: array items: - $ref: '#/components/schemas/User' + $ref: '../common_attributes.schema.yaml#/components/schemas/User' messages: type: array items: @@ -224,9 +201,7 @@ components: - id properties: id: - oneOf: - - $ref: '#/components/schemas/UUID' - - $ref: '#/components/schemas/NonEmptyString' + $ref: '../common_attributes.schema.yaml#/components/schemas/NonEmptyString' title: type: string description: The conversation title. diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/crud_conversation_route.gen.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/crud_conversation_route.gen.ts index ed5f1b8f057c6..072a04d944d34 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/crud_conversation_route.gen.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/crud_conversation_route.gen.ts @@ -13,16 +13,16 @@ import { z } from 'zod'; * * info: * title: Create Conversation API endpoint - * version: 2023-10-31 + * version: 1 */ import { ConversationCreateProps, ConversationResponse, - UUID, ConversationUpdateProps, ConversationMessageCreateProps, } from './common_attributes.gen'; +import { NonEmptyString } from '../common_attributes.gen'; export type AppendConversationMessageRequestParams = z.infer< typeof AppendConversationMessageRequestParams @@ -31,7 +31,7 @@ export const AppendConversationMessageRequestParams = z.object({ /** * The conversation's `id` value. */ - id: UUID, + id: NonEmptyString, }); export type AppendConversationMessageRequestParamsInput = z.input< typeof AppendConversationMessageRequestParams @@ -60,7 +60,7 @@ export const DeleteConversationRequestParams = z.object({ /** * The conversation's `id` value. */ - id: UUID, + id: NonEmptyString, }); export type DeleteConversationRequestParamsInput = z.input; @@ -72,7 +72,7 @@ export const ReadConversationRequestParams = z.object({ /** * The conversation's `id` value. */ - id: UUID, + id: NonEmptyString, }); export type ReadConversationRequestParamsInput = z.input; @@ -84,7 +84,7 @@ export const UpdateConversationRequestParams = z.object({ /** * The conversation's `id` value. */ - id: UUID, + id: NonEmptyString, }); export type UpdateConversationRequestParamsInput = z.input; diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/crud_conversation_route.schema.yaml b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/crud_conversation_route.schema.yaml index a7f08659e76e3..fc2f86e8a8654 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/crud_conversation_route.schema.yaml +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/crud_conversation_route.schema.yaml @@ -1,9 +1,9 @@ openapi: 3.0.0 info: title: Create Conversation API endpoint - version: '2023-10-31' + version: '1' paths: - /api/elastic_assistant/conversations: + /internal/elastic_assistant/conversations: post: operationId: CreateConversation x-codegen-enabled: true @@ -37,8 +37,8 @@ paths: type: string message: type: string - - /api/elastic_assistant/conversations/{id}: + + /internal/elastic_assistant/conversations/{id}: get: operationId: ReadConversation x-codegen-enabled: true @@ -52,7 +52,7 @@ paths: required: true description: The conversation's `id` value. schema: - $ref: './common_attributes.schema.yaml#/components/schemas/UUID' + $ref: '../common_attributes.schema.yaml#/components/schemas/NonEmptyString' responses: 200: description: Indicates a successful call. @@ -86,7 +86,7 @@ paths: required: true description: The conversation's `id` value. schema: - $ref: './common_attributes.schema.yaml#/components/schemas/UUID' + $ref: '../common_attributes.schema.yaml#/components/schemas/NonEmptyString' requestBody: required: true content: @@ -126,7 +126,7 @@ paths: required: true description: The conversation's `id` value. schema: - $ref: './common_attributes.schema.yaml#/components/schemas/UUID' + $ref: '../common_attributes.schema.yaml#/components/schemas/NonEmptyString' responses: 200: description: Indicates a successful call. @@ -147,8 +147,8 @@ paths: type: string message: type: string - - /api/elastic_assistant/conversations/{id}/messages: + + /internal/elastic_assistant/conversations/{id}/messages: post: operationId: AppendConversationMessage x-codegen-enabled: true @@ -162,7 +162,7 @@ paths: required: true description: The conversation's `id` value. schema: - $ref: './common_attributes.schema.yaml#/components/schemas/UUID' + $ref: '../common_attributes.schema.yaml#/components/schemas/NonEmptyString' requestBody: required: true content: @@ -188,4 +188,4 @@ paths: error: type: string message: - type: string \ No newline at end of file + type: string diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.gen.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.gen.ts index 16743f77b3efd..8f840c69adf30 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.gen.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.gen.ts @@ -14,7 +14,7 @@ import { ArrayFromString } from '@kbn/zod-helpers'; * * info: * title: Find Conversations API endpoint - * version: 2023-10-31 + * version: 1 */ import { ConversationResponse } from './common_attributes.gen'; diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.schema.yaml b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.schema.yaml index b44cebd1d3ec2..44cec1a169e51 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.schema.yaml +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/conversations/find_conversations_route.schema.yaml @@ -1,9 +1,9 @@ openapi: 3.0.0 info: title: Find Conversations API endpoint - version: '2023-10-31' + version: '1' paths: - /api/elastic_assistant/conversations/_find: + /internal/elastic_assistant/conversations/_find: get: operationId: FindConversations x-codegen-enabled: true @@ -91,7 +91,7 @@ paths: message: type: string - /api/elastic_assistant/conversations/current_user/_find: + /internal/elastic_assistant/conversations/current_user/_find: get: operationId: FindCurrentUserConversations x-codegen-enabled: true diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/index.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/index.ts index 24d484bdd06c6..c9c2d2a8be3c0 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/index.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/index.ts @@ -18,6 +18,9 @@ export const API_VERSIONS = { export const PUBLIC_API_ACCESS = 'public'; export const INTERNAL_API_ACCESS = 'internal'; +// Common Schemas +export * from './common_attributes.gen'; + // Attack discovery Schemas export * from './attack_discovery/post_attack_discovery_route.gen'; @@ -37,5 +40,8 @@ export * from './conversations/find_conversations_route.gen'; // Actions Connector Schemas export * from './actions_connector/post_actions_connector_execute_route.gen'; -// KB Schemas +// Knowledge Base Schemas export * from './knowledge_base/crud_kb_route.gen'; +export * from './knowledge_base/bulk_crud_knowledge_base_route.gen'; +export * from './knowledge_base/common_attributes.gen'; +export * from './knowledge_base/crud_knowledge_base_route.gen'; diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/bulk_crud_knowledge_base_route.gen.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/bulk_crud_knowledge_base_route.gen.ts new file mode 100644 index 0000000000000..9ff055e656fe3 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/bulk_crud_knowledge_base_route.gen.ts @@ -0,0 +1,117 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { z } from 'zod'; + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Bulk Knowledge Base Actions API endpoint + * version: 2023-10-31 + */ + +import { + KnowledgeBaseEntryCreateProps, + KnowledgeBaseEntryUpdateProps, + KnowledgeBaseEntryResponse, +} from './common_attributes.gen'; + +export type KnowledgeBaseEntryBulkActionSkipReason = z.infer< + typeof KnowledgeBaseEntryBulkActionSkipReason +>; +export const KnowledgeBaseEntryBulkActionSkipReason = z.literal( + 'KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED' +); + +export type KnowledgeBaseEntryBulkActionSkipResult = z.infer< + typeof KnowledgeBaseEntryBulkActionSkipResult +>; +export const KnowledgeBaseEntryBulkActionSkipResult = z.object({ + id: z.string(), + name: z.string().optional(), + skip_reason: KnowledgeBaseEntryBulkActionSkipReason, +}); + +export type KnowledgeBaseEntryDetailsInError = z.infer; +export const KnowledgeBaseEntryDetailsInError = z.object({ + id: z.string(), + name: z.string().optional(), +}); + +export type NormalizedKnowledgeBaseEntryError = z.infer; +export const NormalizedKnowledgeBaseEntryError = z.object({ + message: z.string(), + statusCode: z.number().int(), + err_code: z.string().optional(), + knowledgeBaseEntries: z.array(KnowledgeBaseEntryDetailsInError), +}); + +export type KnowledgeBaseEntryBulkCrudActionResults = z.infer< + typeof KnowledgeBaseEntryBulkCrudActionResults +>; +export const KnowledgeBaseEntryBulkCrudActionResults = z.object({ + updated: z.array(KnowledgeBaseEntryResponse), + created: z.array(KnowledgeBaseEntryResponse), + deleted: z.array(z.string()), + skipped: z.array(KnowledgeBaseEntryBulkActionSkipResult), +}); + +export type KnowledgeBaseEntryBulkCrudActionSummary = z.infer< + typeof KnowledgeBaseEntryBulkCrudActionSummary +>; +export const KnowledgeBaseEntryBulkCrudActionSummary = z.object({ + failed: z.number().int(), + skipped: z.number().int(), + succeeded: z.number().int(), + total: z.number().int(), +}); + +export type KnowledgeBaseEntryBulkCrudActionResponse = z.infer< + typeof KnowledgeBaseEntryBulkCrudActionResponse +>; +export const KnowledgeBaseEntryBulkCrudActionResponse = z.object({ + success: z.boolean().optional(), + statusCode: z.number().int().optional(), + message: z.string().optional(), + knowledgeBaseEntriesCount: z.number().int().optional(), + attributes: z.object({ + results: KnowledgeBaseEntryBulkCrudActionResults, + summary: KnowledgeBaseEntryBulkCrudActionSummary, + errors: z.array(NormalizedKnowledgeBaseEntryError).optional(), + }), +}); + +export type KnowledgeBaseEntryBulkActionBase = z.infer; +export const KnowledgeBaseEntryBulkActionBase = z.object({ + /** + * Query to filter Knowledge Base Entries + */ + query: z.string().optional(), + /** + * Array of Knowledge base Entry IDs + */ + ids: z.array(z.string()).min(1).optional(), +}); + +export type PerformKnowledgeBaseEntryBulkActionRequestBody = z.infer< + typeof PerformKnowledgeBaseEntryBulkActionRequestBody +>; +export const PerformKnowledgeBaseEntryBulkActionRequestBody = z.object({ + delete: KnowledgeBaseEntryBulkActionBase.optional(), + create: z.array(KnowledgeBaseEntryCreateProps).optional(), + update: z.array(KnowledgeBaseEntryUpdateProps).optional(), +}); +export type PerformKnowledgeBaseEntryBulkActionRequestBodyInput = z.input< + typeof PerformKnowledgeBaseEntryBulkActionRequestBody +>; + +export type PerformKnowledgeBaseEntryBulkActionResponse = z.infer< + typeof PerformKnowledgeBaseEntryBulkActionResponse +>; +export const PerformKnowledgeBaseEntryBulkActionResponse = KnowledgeBaseEntryBulkCrudActionResponse; diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/bulk_crud_knowledge_base_route.schema.yaml b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/bulk_crud_knowledge_base_route.schema.yaml new file mode 100644 index 0000000000000..f8a2ee49d399a --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/bulk_crud_knowledge_base_route.schema.yaml @@ -0,0 +1,175 @@ +openapi: 3.0.0 +info: + title: Bulk Knowledge Base Actions API endpoint + version: '2023-10-31' +paths: + /api/elastic_assistant/knowledge_base/entries/_bulk_action: + post: + operationId: PerformKnowledgeBaseEntryBulkAction + x-codegen-enabled: true + summary: Applies a bulk action to multiple Knowledge Base Entries + description: The bulk action is applied to all Knowledge Base Entries that match the filter or to the list of Knowledge Base Entries by their IDs + tags: + - Knowledge Base Entries Bulk API + requestBody: + content: + application/json: + schema: + type: object + properties: + delete: + $ref: '#/components/schemas/KnowledgeBaseEntryBulkActionBase' + create: + type: array + items: + $ref: './common_attributes.schema.yaml#/components/schemas/KnowledgeBaseEntryCreateProps' + update: + type: array + items: + $ref: './common_attributes.schema.yaml#/components/schemas/KnowledgeBaseEntryUpdateProps' + responses: + 200: + description: Successful bulk operation request + content: + application/json: + schema: + $ref: '#/components/schemas/KnowledgeBaseEntryBulkCrudActionResponse' + 400: + description: Generic Error + content: + application/json: + schema: + $ref: './common_attributes.schema.yaml#/components/schemas/KnowledgeBaseEntryErrorSchema' + +components: + schemas: + KnowledgeBaseEntryBulkActionSkipReason: + type: string + enum: + - KNOWLEDGE_BASE_ENTRY_NOT_MODIFIED + + KnowledgeBaseEntryBulkActionSkipResult: + type: object + properties: + id: + type: string + name: + type: string + skip_reason: + $ref: '#/components/schemas/KnowledgeBaseEntryBulkActionSkipReason' + required: + - id + - skip_reason + + KnowledgeBaseEntryDetailsInError: + type: object + properties: + id: + type: string + name: + type: string + required: + - id + + NormalizedKnowledgeBaseEntryError: + type: object + properties: + message: + type: string + statusCode: + type: integer + err_code: + type: string + knowledgeBaseEntries: + type: array + items: + $ref: '#/components/schemas/KnowledgeBaseEntryDetailsInError' + required: + - message + - statusCode + - knowledgeBaseEntries + + KnowledgeBaseEntryBulkCrudActionResults: + type: object + properties: + updated: + type: array + items: + $ref: './common_attributes.schema.yaml#/components/schemas/KnowledgeBaseEntryResponse' + created: + type: array + items: + $ref: './common_attributes.schema.yaml#/components/schemas/KnowledgeBaseEntryResponse' + deleted: + type: array + items: + type: string + skipped: + type: array + items: + $ref: '#/components/schemas/KnowledgeBaseEntryBulkActionSkipResult' + required: + - updated + - created + - deleted + - skipped + + KnowledgeBaseEntryBulkCrudActionSummary: + type: object + properties: + failed: + type: integer + skipped: + type: integer + succeeded: + type: integer + total: + type: integer + required: + - failed + - skipped + - succeeded + - total + + KnowledgeBaseEntryBulkCrudActionResponse: + type: object + properties: + success: + type: boolean + statusCode: + type: integer + message: + type: string + knowledgeBaseEntriesCount: + type: integer + attributes: + type: object + properties: + results: + $ref: '#/components/schemas/KnowledgeBaseEntryBulkCrudActionResults' + summary: + $ref: '#/components/schemas/KnowledgeBaseEntryBulkCrudActionSummary' + errors: + type: array + items: + $ref: '#/components/schemas/NormalizedKnowledgeBaseEntryError' + required: + - results + - summary + required: + - attributes + + + KnowledgeBaseEntryBulkActionBase: + x-inline: true + type: object + properties: + query: + type: string + description: Query to filter Knowledge Base Entries + ids: + type: array + description: Array of Knowledge base Entry IDs + minItems: 1 + items: + type: string diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/common_attributes.gen.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/common_attributes.gen.ts new file mode 100644 index 0000000000000..0d44cbe51e320 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/common_attributes.gen.ts @@ -0,0 +1,119 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { z } from 'zod'; + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Common Knowledge Base Attributes + * version: not applicable + */ + +import { NonEmptyString, User } from '../common_attributes.gen'; + +export type KnowledgeBaseEntryErrorSchema = z.infer; +export const KnowledgeBaseEntryErrorSchema = z + .object({ + statusCode: z.number(), + error: z.string(), + message: z.string(), + }) + .strict(); + +/** + * Metadata about an Knowledge Base Entry + */ +export type Metadata = z.infer; +export const Metadata = z.object({ + /** + * Knowledge Base resource name + */ + kbResource: z.string(), + /** + * Original text content source + */ + source: z.string(), + /** + * Whether or not this resource should always be included + */ + required: z.boolean(), +}); + +/** + * Object containing Knowledge Base Entry text embeddings and modelId used to create the embeddings + */ +export type Vector = z.infer; +export const Vector = z.object({ + /** + * ID of the model used to create the embeddings + */ + modelId: z.string(), + /** + * Tokens with their corresponding values + */ + tokens: z.object({}).catchall(z.number()), +}); + +export type KnowledgeBaseEntryResponse = z.infer; +export const KnowledgeBaseEntryResponse = z.object({ + timestamp: NonEmptyString.optional(), + id: NonEmptyString, + /** + * Time the Knowledge Base Entry was created + */ + createdAt: z.string(), + /** + * User who created the Knowledge Base Entry + */ + createdBy: z.string().optional(), + /** + * Time the Knowledge Base Entry was last updated + */ + updatedAt: z.string().optional(), + /** + * User who last updated the Knowledge Base Entry + */ + updatedBy: z.string().optional(), + users: z.array(User), + /** + * Metadata about the Knowledge Base Entry + */ + metadata: Metadata.optional(), + /** + * Kibana space + */ + namespace: z.string(), + /** + * Knowledge Base Entry content + */ + text: z.string(), + vector: Vector.optional(), +}); + +export type KnowledgeBaseEntryUpdateProps = z.infer; +export const KnowledgeBaseEntryUpdateProps = z.object({ + id: NonEmptyString, + /** + * Metadata about the Knowledge Base Entry + */ + metadata: Metadata.optional(), +}); + +export type KnowledgeBaseEntryCreateProps = z.infer; +export const KnowledgeBaseEntryCreateProps = z.object({ + /** + * Metadata about the Knowledge Base Entry + */ + metadata: Metadata, + /** + * Knowledge Base Entry content + */ + text: z.string(), +}); diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/common_attributes.schema.yaml b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/common_attributes.schema.yaml new file mode 100644 index 0000000000000..a9a9794852953 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/common_attributes.schema.yaml @@ -0,0 +1,124 @@ +openapi: 3.0.0 +info: + title: Common Knowledge Base Attributes + version: 'not applicable' +paths: {} +components: + x-codegen-enabled: true + schemas: + + KnowledgeBaseEntryErrorSchema: + type: object + required: + - statusCode + - error + - message + additionalProperties: false + properties: + statusCode: + type: number + error: + type: string + message: + type: string + + Metadata: + type: object + description: Metadata about an Knowledge Base Entry + required: + - 'kbResource' + - 'source' + - 'required' + properties: + kbResource: + type: string + description: Knowledge Base resource name + source: + type: string + description: Original text content source + required: + type: boolean + description: Whether or not this resource should always be included + + Vector: + type: object + description: Object containing Knowledge Base Entry text embeddings and modelId used to create the embeddings + required: + - 'modelId' + - 'tokens' + properties: + modelId: + type: string + description: ID of the model used to create the embeddings + tokens: + type: object + additionalProperties: + type: number + description: Tokens with their corresponding values + + KnowledgeBaseEntryResponse: + type: object + required: + - id + - createdAt + - users + - namespace + - text + properties: + 'timestamp': + $ref: '../common_attributes.schema.yaml#/components/schemas/NonEmptyString' + id: + $ref: '../common_attributes.schema.yaml#/components/schemas/NonEmptyString' + createdAt: + description: Time the Knowledge Base Entry was created + type: string + createdBy: + description: User who created the Knowledge Base Entry + type: string + updatedAt: + description: Time the Knowledge Base Entry was last updated + type: string + updatedBy: + description: User who last updated the Knowledge Base Entry + type: string + users: + type: array + items: + $ref: '../common_attributes.schema.yaml#/components/schemas/User' + metadata: + $ref: '#/components/schemas/Metadata' + description: Metadata about the Knowledge Base Entry + namespace: + type: string + description: Kibana space + text: + type: string + description: Knowledge Base Entry content + vector: + $ref: '#/components/schemas/Vector' + + KnowledgeBaseEntryUpdateProps: + type: object + required: + - id + properties: + id: + $ref: '../common_attributes.schema.yaml#/components/schemas/NonEmptyString' + metadata: + $ref: '#/components/schemas/Metadata' + description: Metadata about the Knowledge Base Entry + + KnowledgeBaseEntryCreateProps: + type: object + required: + - metadata + - text + properties: + metadata: + $ref: '#/components/schemas/Metadata' + description: Metadata about the Knowledge Base Entry + text: + type: string + description: Knowledge Base Entry content + + diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.gen.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.gen.ts index 634cd8cb6e78b..8c85cbce32108 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.gen.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.gen.ts @@ -67,6 +67,8 @@ export type ReadKnowledgeBaseRequestParamsInput = z.input; export const ReadKnowledgeBaseResponse = z.object({ elser_exists: z.boolean().optional(), + esql_exists: z.boolean().optional(), index_exists: z.boolean().optional(), + is_setup_in_progress: z.boolean().optional(), pipeline_exists: z.boolean().optional(), }); diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.schema.yaml b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.schema.yaml index 650a7e141ce39..16d13c24f23ea 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.schema.yaml +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_kb_route.schema.yaml @@ -60,8 +60,12 @@ paths: properties: elser_exists: type: boolean + esql_exists: + type: boolean index_exists: type: boolean + is_setup_in_progress: + type: boolean pipeline_exists: type: boolean 400: diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_knowledge_base_route.gen.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_knowledge_base_route.gen.ts new file mode 100644 index 0000000000000..92523a43b8e76 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_knowledge_base_route.gen.ts @@ -0,0 +1,91 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { z } from 'zod'; + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Manage Knowledge Base Entries API endpoint + * version: 2023-10-31 + */ + +import { + KnowledgeBaseEntryCreateProps, + KnowledgeBaseEntryResponse, + KnowledgeBaseEntryUpdateProps, +} from './common_attributes.gen'; +import { NonEmptyString } from '../common_attributes.gen'; + +export type CreateKnowledgeBaseEntryRequestBody = z.infer< + typeof CreateKnowledgeBaseEntryRequestBody +>; +export const CreateKnowledgeBaseEntryRequestBody = KnowledgeBaseEntryCreateProps; +export type CreateKnowledgeBaseEntryRequestBodyInput = z.input< + typeof CreateKnowledgeBaseEntryRequestBody +>; + +export type CreateKnowledgeBaseEntryResponse = z.infer; +export const CreateKnowledgeBaseEntryResponse = KnowledgeBaseEntryResponse; + +export type DeleteKnowledgeBaseEntryRequestParams = z.infer< + typeof DeleteKnowledgeBaseEntryRequestParams +>; +export const DeleteKnowledgeBaseEntryRequestParams = z.object({ + /** + * The Knowledge Base Entry's `id` value + */ + id: NonEmptyString, +}); +export type DeleteKnowledgeBaseEntryRequestParamsInput = z.input< + typeof DeleteKnowledgeBaseEntryRequestParams +>; + +export type DeleteKnowledgeBaseEntryResponse = z.infer; +export const DeleteKnowledgeBaseEntryResponse = KnowledgeBaseEntryResponse; + +export type ReadKnowledgeBaseEntryRequestParams = z.infer< + typeof ReadKnowledgeBaseEntryRequestParams +>; +export const ReadKnowledgeBaseEntryRequestParams = z.object({ + /** + * The Knowledge Base Entry's `id` value. + */ + id: NonEmptyString, +}); +export type ReadKnowledgeBaseEntryRequestParamsInput = z.input< + typeof ReadKnowledgeBaseEntryRequestParams +>; + +export type ReadKnowledgeBaseEntryResponse = z.infer; +export const ReadKnowledgeBaseEntryResponse = KnowledgeBaseEntryResponse; + +export type UpdateKnowledgeBaseEntryRequestParams = z.infer< + typeof UpdateKnowledgeBaseEntryRequestParams +>; +export const UpdateKnowledgeBaseEntryRequestParams = z.object({ + /** + * The Knowledge Base Entry's `id` value + */ + id: NonEmptyString, +}); +export type UpdateKnowledgeBaseEntryRequestParamsInput = z.input< + typeof UpdateKnowledgeBaseEntryRequestParams +>; + +export type UpdateKnowledgeBaseEntryRequestBody = z.infer< + typeof UpdateKnowledgeBaseEntryRequestBody +>; +export const UpdateKnowledgeBaseEntryRequestBody = KnowledgeBaseEntryUpdateProps; +export type UpdateKnowledgeBaseEntryRequestBodyInput = z.input< + typeof UpdateKnowledgeBaseEntryRequestBody +>; + +export type UpdateKnowledgeBaseEntryResponse = z.infer; +export const UpdateKnowledgeBaseEntryResponse = KnowledgeBaseEntryResponse; diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_knowledge_base_route.schema.yaml b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_knowledge_base_route.schema.yaml new file mode 100644 index 0000000000000..6db7da89f55e5 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/knowledge_base/crud_knowledge_base_route.schema.yaml @@ -0,0 +1,122 @@ +openapi: 3.0.0 +info: + title: Manage Knowledge Base Entries API endpoint + version: '2023-10-31' +paths: + /api/elastic_assistant/knowledge_base/entries: + post: + operationId: CreateKnowledgeBaseEntry + x-codegen-enabled: true + description: Create a Knowledge Base Entry + summary: Create a Knowledge Base Entry + tags: + - Knowledge Base Entries API + requestBody: + required: true + content: + application/json: + schema: + $ref: './common_attributes.schema.yaml#/components/schemas/KnowledgeBaseEntryCreateProps' + responses: + 200: + description: Successful request returning Knowledge Base Entries + content: + application/json: + schema: + $ref: './common_attributes.schema.yaml#/components/schemas/KnowledgeBaseEntryResponse' + 400: + description: Generic Error + content: + application/json: + schema: + $ref: './common_attributes.schema.yaml#/components/schemas/KnowledgeBaseEntryErrorSchema' + + /api/elastic_assistant/knowledge_base/entries/{id}: + get: + operationId: ReadKnowledgeBaseEntry + x-codegen-enabled: true + description: Read a Knowledge Base Entry + summary: Read a Knowledge Base Entry + tags: + - Knowledge Base Entries API + parameters: + - name: id + in: path + required: true + description: The Knowledge Base Entry's `id` value. + schema: + $ref: '../common_attributes.schema.yaml#/components/schemas/NonEmptyString' + responses: + 200: + description: Successful request returning a Knowledge Base Entry + content: + application/json: + schema: + $ref: './common_attributes.schema.yaml#/components/schemas/KnowledgeBaseEntryResponse' + 400: + description: Generic Error + content: + application/json: + schema: + $ref: './common_attributes.schema.yaml#/components/schemas/KnowledgeBaseEntryErrorSchema' + put: + operationId: UpdateKnowledgeBaseEntry + x-codegen-enabled: true + description: Update a Knowledge Base Entry + summary: Update a Knowledge Base Entry + tags: + - Knowledge Base Entries API + parameters: + - name: id + in: path + required: true + description: The Knowledge Base Entry's `id` value + schema: + $ref: '../common_attributes.schema.yaml#/components/schemas/NonEmptyString' + requestBody: + required: true + content: + application/json: + schema: + $ref: './common_attributes.schema.yaml#/components/schemas/KnowledgeBaseEntryUpdateProps' + responses: + 200: + description: Successful request returning the updated Knowledge Base Entry + content: + application/json: + schema: + $ref: './common_attributes.schema.yaml#/components/schemas/KnowledgeBaseEntryResponse' + 400: + description: Generic Error + content: + application/json: + schema: + $ref: './common_attributes.schema.yaml#/components/schemas/KnowledgeBaseEntryErrorSchema' + delete: + operationId: DeleteKnowledgeBaseEntry + x-codegen-enabled: true + description: Deletes a single Knowledge Base Entry using the `id` field + summary: Deletes a single Knowledge Base Entry using the `id` field + tags: + - Knowledge Base Entries API + parameters: + - name: id + in: path + required: true + description: The Knowledge Base Entry's `id` value + schema: + $ref: '../common_attributes.schema.yaml#/components/schemas/NonEmptyString' + responses: + 200: + description: Successful request returning the deleted Knowledge Base Entry + content: + application/json: + schema: + $ref: './common_attributes.schema.yaml#/components/schemas/KnowledgeBaseEntryResponse' + 400: + description: Generic Error + content: + application/json: + schema: + $ref: './common_attributes.schema.yaml#/components/schemas/KnowledgeBaseEntryErrorSchema' + diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/prompts/bulk_crud_prompts_route.gen.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/prompts/bulk_crud_prompts_route.gen.ts index ce54c6a41fecc..123665bbb582f 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/prompts/bulk_crud_prompts_route.gen.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/prompts/bulk_crud_prompts_route.gen.ts @@ -13,10 +13,10 @@ import { z } from 'zod'; * * info: * title: Bulk Actions API endpoint - * version: 2023-10-31 + * version: 1 */ -import { UUID, NonEmptyString, User } from '../conversations/common_attributes.gen'; +import { NonEmptyString, User } from '../common_attributes.gen'; export type BulkActionSkipReason = z.infer; export const BulkActionSkipReason = z.literal('PROMPT_FIELD_NOT_MODIFIED'); @@ -44,7 +44,7 @@ export const NormalizedPromptError = z.object({ export type PromptResponse = z.infer; export const PromptResponse = z.object({ - id: UUID, + id: NonEmptyString, timestamp: NonEmptyString.optional(), name: z.string(), promptType: z.string(), diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/prompts/bulk_crud_prompts_route.schema.yaml b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/prompts/bulk_crud_prompts_route.schema.yaml index 2f6a419d9bf2c..ede0136ba710a 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/prompts/bulk_crud_prompts_route.schema.yaml +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/prompts/bulk_crud_prompts_route.schema.yaml @@ -1,9 +1,9 @@ openapi: 3.0.0 info: title: Bulk Actions API endpoint - version: '2023-10-31' + version: '1' paths: - /api/elastic_assistant/prompts/_bulk_action: + /internal/elastic_assistant/prompts/_bulk_action: post: operationId: PerformBulkAction x-codegen-enabled: true @@ -105,9 +105,9 @@ components: - content properties: id: - $ref: '../conversations/common_attributes.schema.yaml#/components/schemas/UUID' + $ref: '../common_attributes.schema.yaml#/components/schemas/NonEmptyString' 'timestamp': - $ref: '../conversations/common_attributes.schema.yaml#/components/schemas/NonEmptyString' + $ref: '../common_attributes.schema.yaml#/components/schemas/NonEmptyString' name: type: string promptType: @@ -131,7 +131,7 @@ components: users: type: array items: - $ref: '../conversations/common_attributes.schema.yaml#/components/schemas/User' + $ref: '../common_attributes.schema.yaml#/components/schemas/User' namespace: type: string description: Kibana space @@ -256,4 +256,3 @@ components: type: boolean isShared: type: boolean - \ No newline at end of file diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/prompts/find_prompts_route.gen.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/prompts/find_prompts_route.gen.ts index 7400b11f25c7a..2a7a87ecf1094 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/prompts/find_prompts_route.gen.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/prompts/find_prompts_route.gen.ts @@ -14,7 +14,7 @@ import { ArrayFromString } from '@kbn/zod-helpers'; * * info: * title: Find Prompts API endpoint - * version: 2023-10-31 + * version: 1 */ import { PromptResponse } from './bulk_crud_prompts_route.gen'; diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/prompts/find_prompts_route.schema.yaml b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/prompts/find_prompts_route.schema.yaml index b5d3b25ca2018..8e85194811dbc 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/prompts/find_prompts_route.schema.yaml +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/schemas/prompts/find_prompts_route.schema.yaml @@ -1,9 +1,9 @@ openapi: 3.0.0 info: title: Find Prompts API endpoint - version: '2023-10-31' + version: '1' paths: - /api/elastic_assistant/prompts/_find: + /internal/elastic_assistant/prompts/_find: get: operationId: FindPrompts x-codegen-enabled: true diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/utils/bedrock.ts b/x-pack/packages/kbn-elastic-assistant-common/impl/utils/bedrock.ts index 273cb80732517..ab3756d43dc0e 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/utils/bedrock.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/impl/utils/bedrock.ts @@ -5,10 +5,30 @@ * 2.0. */ -import { Logger } from '@kbn/core/server'; +import { Logger } from '@kbn/logging'; import { EventStreamCodec } from '@smithy/eventstream-codec'; import { fromUtf8, toUtf8 } from '@smithy/util-utf8'; +/** + * Parses a Bedrock buffer from an array of chunks. + * + * @param {Uint8Array[]} chunks - Array of Uint8Array chunks to be parsed. + * @returns {string} - Parsed string from the Bedrock buffer. + */ +export const parseBedrockBuffer = (chunks: Uint8Array[], logger: Logger): string => { + // Initialize an empty Uint8Array to store the concatenated buffer. + let bedrockBuffer: Uint8Array = new Uint8Array(0); + + // Map through each chunk to process the Bedrock buffer. + return chunks + .map((chunk) => { + const processedChunk = handleBedrockChunk({ chunk, bedrockBuffer, logger }); + bedrockBuffer = processedChunk.bedrockBuffer; + return processedChunk.decodedChunk; + }) + .join(''); +}; + /** * Handle a chunk of data from the bedrock API. * @param chunk - The chunk of data to process. @@ -55,7 +75,9 @@ export const handleBedrockChunk = ({ Buffer.from(JSON.parse(new TextDecoder().decode(event.body)).bytes, 'base64').toString() ); const decodedContent = prepareBedrockOutput(body, logger); - if (chunkHandler) chunkHandler(decodedContent); + if (chunkHandler) { + chunkHandler(decodedContent); + } return decodedContent; }) .join(''); diff --git a/x-pack/packages/kbn-elastic-assistant-common/index.ts b/x-pack/packages/kbn-elastic-assistant-common/index.ts index 48f8d9cd9714b..d8b4858d3ba8b 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/index.ts +++ b/x-pack/packages/kbn-elastic-assistant-common/index.ts @@ -23,6 +23,5 @@ export { } from './impl/data_anonymization/helpers'; export { transformRawData } from './impl/data_anonymization/transform_raw_data'; -export { handleBedrockChunk } from './impl/utils/bedrock'; - +export { parseBedrockBuffer, handleBedrockChunk } from './impl/utils/bedrock'; export * from './constants'; diff --git a/x-pack/packages/kbn-elastic-assistant-common/tsconfig.json b/x-pack/packages/kbn-elastic-assistant-common/tsconfig.json index 73f57730b9a67..02f5f7b3babd5 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/tsconfig.json +++ b/x-pack/packages/kbn-elastic-assistant-common/tsconfig.json @@ -19,7 +19,6 @@ "@kbn/zod-helpers", "@kbn/securitysolution-io-ts-utils", "@kbn/core", - "@kbn/actions-plugin", - "@kbn/logging-mocks", + "@kbn/logging", ] } diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/anonymization_fields/bulk_update_anonymization_fields.test.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/anonymization_fields/bulk_update_anonymization_fields.test.ts index 88e9c0febba13..544c8c1606c3d 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/anonymization_fields/bulk_update_anonymization_fields.test.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/anonymization_fields/bulk_update_anonymization_fields.test.ts @@ -48,7 +48,7 @@ describe('bulkUpdateAnonymizationFields', () => { ELASTIC_AI_ASSISTANT_ANONYMIZATION_FIELDS_URL_BULK_ACTION, { method: 'POST', - version: API_VERSIONS.public.v1, + version: API_VERSIONS.internal.v1, body: JSON.stringify({ create: [], update: [], @@ -71,7 +71,7 @@ describe('bulkUpdateAnonymizationFields', () => { ELASTIC_AI_ASSISTANT_ANONYMIZATION_FIELDS_URL_BULK_ACTION, { method: 'POST', - version: API_VERSIONS.public.v1, + version: API_VERSIONS.internal.v1, body: JSON.stringify({ create: [anonymizationField1, anonymizationField2], update: [], @@ -93,7 +93,7 @@ describe('bulkUpdateAnonymizationFields', () => { ELASTIC_AI_ASSISTANT_ANONYMIZATION_FIELDS_URL_BULK_ACTION, { method: 'POST', - version: API_VERSIONS.public.v1, + version: API_VERSIONS.internal.v1, body: JSON.stringify({ update: [anonymizationField1, anonymizationField2], delete: { ids: [] }, diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/anonymization_fields/bulk_update_anonymization_fields.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/anonymization_fields/bulk_update_anonymization_fields.ts index 9745e7ce38662..72d73cc2a5929 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/anonymization_fields/bulk_update_anonymization_fields.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/anonymization_fields/bulk_update_anonymization_fields.ts @@ -26,7 +26,7 @@ export const bulkUpdateAnonymizationFields = async ( ELASTIC_AI_ASSISTANT_ANONYMIZATION_FIELDS_URL_BULK_ACTION, { method: 'POST', - version: API_VERSIONS.public.v1, + version: API_VERSIONS.internal.v1, body: JSON.stringify(anonymizationFieldsActions), } ); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/anonymization_fields/use_fetch_anonymization_fields.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/anonymization_fields/use_fetch_anonymization_fields.test.tsx index aabdcb6909ccb..7c10597eaed87 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/anonymization_fields/use_fetch_anonymization_fields.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/anonymization_fields/use_fetch_anonymization_fields.test.tsx @@ -13,11 +13,10 @@ import React from 'react'; import { useFetchAnonymizationFields } from './use_fetch_anonymization_fields'; import { HttpSetup } from '@kbn/core-http-browser'; import { useAssistantContext } from '../../../assistant_context'; - -const statusResponse = { assistantModelEvaluation: true, assistantStreamingEnabled: false }; +import { API_VERSIONS, defaultAssistantFeatures } from '@kbn/elastic-assistant-common'; const http = { - fetch: jest.fn().mockResolvedValue(statusResponse), + fetch: jest.fn().mockResolvedValue(defaultAssistantFeatures), } as unknown as HttpSetup; jest.mock('../../../assistant_context'); @@ -45,15 +44,18 @@ describe('useFetchAnonymizationFields', () => { await act(async () => { const { waitForNextUpdate } = renderHook(() => useFetchAnonymizationFields()); await waitForNextUpdate(); - expect(http.fetch).toHaveBeenCalledWith('/api/elastic_assistant/anonymization_fields/_find', { - method: 'GET', - query: { - page: 1, - per_page: 1000, - }, - version: '2023-10-31', - signal: undefined, - }); + expect(http.fetch).toHaveBeenCalledWith( + '/internal/elastic_assistant/anonymization_fields/_find', + { + method: 'GET', + query: { + page: 1, + per_page: 1000, + }, + version: API_VERSIONS.internal.v1, + signal: undefined, + } + ); expect(http.fetch).toHaveBeenCalled(); }); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/anonymization_fields/use_fetch_anonymization_fields.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/anonymization_fields/use_fetch_anonymization_fields.ts index 657216b9079cd..d2f07124f04b0 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/anonymization_fields/use_fetch_anonymization_fields.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/anonymization_fields/use_fetch_anonymization_fields.ts @@ -36,7 +36,7 @@ export const CACHING_KEYS = [ ELASTIC_AI_ASSISTANT_ANONYMIZATION_FIELDS_URL_FIND, QUERY.page, QUERY.per_page, - API_VERSIONS.public.v1, + API_VERSIONS.internal.v1, ]; export const useFetchAnonymizationFields = (payload?: UseFetchAnonymizationFieldsParams) => { @@ -50,7 +50,7 @@ export const useFetchAnonymizationFields = (payload?: UseFetchAnonymizationField async () => http.fetch(ELASTIC_AI_ASSISTANT_ANONYMIZATION_FIELDS_URL_FIND, { method: 'GET', - version: API_VERSIONS.public.v1, + version: API_VERSIONS.internal.v1, query: QUERY, signal: payload?.signal, }), diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/capabilities/__mocks__/use_capabilities.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/capabilities/__mocks__/use_capabilities.tsx new file mode 100644 index 0000000000000..d6dd239d4b6b8 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/capabilities/__mocks__/use_capabilities.tsx @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { defaultAssistantFeatures } from '@kbn/elastic-assistant-common'; + +export const useCapabilities = jest.fn().mockReturnValue({ + isLoading: false, + isError: false, + data: defaultAssistantFeatures, + error: null, + isFetching: false, + isSuccess: true, +}); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/capabilities/use_capabilities.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/capabilities/use_capabilities.test.tsx index 29ad65929bc4c..6101782ae43b1 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/capabilities/use_capabilities.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/capabilities/use_capabilities.test.tsx @@ -11,15 +11,10 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import type { ReactNode } from 'react'; import React from 'react'; import { useCapabilities, UseCapabilitiesParams } from './use_capabilities'; -import { API_VERSIONS } from '@kbn/elastic-assistant-common'; - -const statusResponse = { - assistantModelEvaluation: true, - assistantStreamingEnabled: false, -}; +import { API_VERSIONS, defaultAssistantFeatures } from '@kbn/elastic-assistant-common'; const http = { - get: jest.fn().mockResolvedValue(statusResponse), + get: jest.fn().mockResolvedValue(defaultAssistantFeatures), }; const toasts = { addError: jest.fn(), diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/bulk_update_actions_conversations.test.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/bulk_update_actions_conversations.test.ts index 99cea460fe7d2..a770b90e7881f 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/bulk_update_actions_conversations.test.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/bulk_update_actions_conversations.test.ts @@ -63,7 +63,7 @@ describe('bulkUpdateConversations', () => { ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL_BULK_ACTION, { method: 'POST', - version: API_VERSIONS.public.v1, + version: API_VERSIONS.internal.v1, body: JSON.stringify({ update: [], create: [], @@ -89,7 +89,7 @@ describe('bulkUpdateConversations', () => { ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL_BULK_ACTION, { method: 'POST', - version: API_VERSIONS.public.v1, + version: API_VERSIONS.internal.v1, body: JSON.stringify({ update: [], create: [conversation1, conversation2], @@ -114,7 +114,7 @@ describe('bulkUpdateConversations', () => { ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL_BULK_ACTION, { method: 'POST', - version: API_VERSIONS.public.v1, + version: API_VERSIONS.internal.v1, body: JSON.stringify({ update: [conversation1, conversation2], delete: { ids: [] }, 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 71ebdf50c251d..c22095665a229 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 @@ -114,7 +114,7 @@ export const bulkUpdateConversations = async ( ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL_BULK_ACTION, { method: 'POST', - version: API_VERSIONS.public.v1, + version: API_VERSIONS.internal.v1, body: JSON.stringify({ update: conversationsToUpdate, create: conversationsToCreate, diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/conversations.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/conversations.test.tsx index 0edb5e0f4a158..5f7d7cefaf450 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/conversations.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/conversations.test.tsx @@ -36,11 +36,11 @@ describe('conversations api', () => { await waitForNextUpdate(); expect(deleteProps.http.fetch).toHaveBeenCalledWith( - '/api/elastic_assistant/current_user/conversations/test', + '/internal/elastic_assistant/current_user/conversations/test', { method: 'DELETE', signal: undefined, - version: '2023-10-31', + version: '1', } ); expect(toasts.addError).not.toHaveBeenCalled(); @@ -62,11 +62,11 @@ describe('conversations api', () => { await waitForNextUpdate(); expect(getProps.http.fetch).toHaveBeenCalledWith( - '/api/elastic_assistant/current_user/conversations/test', + '/internal/elastic_assistant/current_user/conversations/test', { method: 'GET', signal: undefined, - version: '2023-10-31', + version: '1', } ); expect(toasts.addError).not.toHaveBeenCalled(); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/conversations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/conversations.ts index 54bac7e563acc..e6c6b2925f337 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/conversations.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/conversations.ts @@ -44,7 +44,7 @@ export const getConversationById = async ({ try { const response = await http.fetch(`${ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL}/${id}`, { method: 'GET', - version: API_VERSIONS.public.v1, + version: API_VERSIONS.internal.v1, signal, }); @@ -84,7 +84,7 @@ export const getUserConversations = async ({ ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL_FIND, { method: 'GET', - version: API_VERSIONS.public.v1, + version: API_VERSIONS.internal.v1, signal, } ); @@ -125,7 +125,7 @@ export const createConversation = async ({ try { const response = await http.post(ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL, { body: JSON.stringify(conversation), - version: API_VERSIONS.public.v1, + version: API_VERSIONS.internal.v1, signal, }); @@ -168,7 +168,7 @@ export const deleteConversation = async ({ try { const response = await http.fetch(`${ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL}/${id}`, { method: 'DELETE', - version: API_VERSIONS.public.v1, + version: API_VERSIONS.internal.v1, signal, }); @@ -237,7 +237,7 @@ export const updateConversation = async ({ headers: { 'Content-Type': 'application/json', }, - version: API_VERSIONS.public.v1, + version: API_VERSIONS.internal.v1, signal, } ); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/use_fetch_current_user_conversations.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/use_fetch_current_user_conversations.test.tsx index 86b39f5ea43be..2c6ed953b56f3 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/use_fetch_current_user_conversations.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/use_fetch_current_user_conversations.test.tsx @@ -14,11 +14,10 @@ import { UseFetchCurrentUserConversationsParams, useFetchCurrentUserConversations, } from './use_fetch_current_user_conversations'; - -const statusResponse = { assistantModelEvaluation: true, assistantStreamingEnabled: false }; +import { defaultAssistantFeatures } from '@kbn/elastic-assistant-common'; const http = { - fetch: jest.fn().mockResolvedValue(statusResponse), + fetch: jest.fn().mockResolvedValue(defaultAssistantFeatures), }; const onFetch = jest.fn(); @@ -48,14 +47,14 @@ describe('useFetchCurrentUserConversations', () => { ); await waitForNextUpdate(); expect(defaultProps.http.fetch).toHaveBeenCalledWith( - '/api/elastic_assistant/current_user/conversations/_find', + '/internal/elastic_assistant/current_user/conversations/_find', { method: 'GET', query: { page: 1, perPage: 100, }, - version: '2023-10-31', + version: '1', signal: undefined, } ); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/use_fetch_current_user_conversations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/use_fetch_current_user_conversations.ts index 68612e3e22397..58be08317d40c 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/use_fetch_current_user_conversations.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/use_fetch_current_user_conversations.ts @@ -47,7 +47,7 @@ export const CONVERSATIONS_QUERY_KEYS = [ ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL_FIND, query.page, query.perPage, - API_VERSIONS.public.v1, + API_VERSIONS.internal.v1, ]; export const useFetchCurrentUserConversations = ({ @@ -62,7 +62,7 @@ export const useFetchCurrentUserConversations = ({ async () => http.fetch(ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL_FIND, { method: 'GET', - version: API_VERSIONS.public.v1, + version: API_VERSIONS.internal.v1, query, signal, }), 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 925ea47ac6ad8..c1c6f8e6a67aa 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 @@ -24,7 +24,7 @@ const mockHttp = { fetch: jest.fn(), } as unknown as HttpSetup; -const apiConfig: Record<'openai' | 'bedrock', ApiConfig> = { +const apiConfig: Record<'openai' | 'bedrock' | 'gemini', ApiConfig> = { openai: { connectorId: 'foo', actionTypeId: '.gen-ai', @@ -35,6 +35,10 @@ const apiConfig: Record<'openai' | 'bedrock', ApiConfig> = { connectorId: 'foo', actionTypeId: '.bedrock', }, + gemini: { + connectorId: 'foo', + actionTypeId: '.gemini', + }, }; const fetchConnectorArgs: FetchConnectorExecuteAction = { @@ -94,7 +98,7 @@ describe('API tests', () => { ); }); - it('calls the non-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 and isEnabledKnowledgeBase is true', async () => { const testProps: FetchConnectorExecuteAction = { ...fetchConnectorArgs, apiConfig: apiConfig.bedrock, @@ -105,13 +109,13 @@ describe('API tests', () => { expect(mockHttp.fetch).toHaveBeenCalledWith( '/internal/elastic_assistant/actions/connector/foo/_execute', { - ...staticDefaults, - body: '{"message":"This is a test","subAction":"invokeAI","conversationId":"test","actionTypeId":".bedrock","replacements":{},"isEnabledKnowledgeBase":true,"isEnabledRAGAlerts":false}', + ...streamingDefaults, + body: '{"message":"This is a test","subAction":"invokeStream","conversationId":"test","actionTypeId":".bedrock","replacements":{},"isEnabledKnowledgeBase":true,"isEnabledRAGAlerts":false}', } ); }); - it('calls the non-stream API when assistantStreamingEnabled is true and actionTypeId is bedrock and isEnabledKnowledgeBase is false and isEnabledRAGAlerts is true', async () => { + 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, @@ -121,11 +125,47 @@ describe('API tests', () => { 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 non-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', + { + ...staticDefaults, + body: '{"message":"This is a test","subAction":"invokeAI","conversationId":"test","actionTypeId":".gemini","replacements":{},"isEnabledKnowledgeBase":true,"isEnabledRAGAlerts":false}', + } + ); + }); + + it('calls the non-stream API when assistantStreamingEnabled is true and actionTypeId is gemini and isEnabledKnowledgeBase is false and isEnabledRAGAlerts is true', async () => { + const testProps: FetchConnectorExecuteAction = { + ...fetchConnectorArgs, + apiConfig: apiConfig.gemini, + isEnabledKnowledgeBase: false, + isEnabledRAGAlerts: true, + }; + + await fetchConnectorExecuteAction(testProps); + expect(mockHttp.fetch).toHaveBeenCalledWith( '/internal/elastic_assistant/actions/connector/foo/_execute', { ...staticDefaults, - body: '{"message":"This is a test","subAction":"invokeAI","conversationId":"test","actionTypeId":".bedrock","replacements":{},"isEnabledKnowledgeBase":false,"isEnabledRAGAlerts":true}', + body: '{"message":"This is a test","subAction":"invokeAI","conversationId":"test","actionTypeId":".gemini","replacements":{},"isEnabledKnowledgeBase":false,"isEnabledRAGAlerts":true}', } ); }); 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 ae465cdf27ba9..fa12841a96152 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 @@ -7,7 +7,18 @@ import { HttpSetup } from '@kbn/core/public'; import { IHttpFetchError } from '@kbn/core-http-browser'; -import { API_VERSIONS, ApiConfig, Replacements } from '@kbn/elastic-assistant-common'; +import { + API_VERSIONS, + ApiConfig, + CreateKnowledgeBaseRequestParams, + CreateKnowledgeBaseResponse, + DeleteKnowledgeBaseRequestParams, + DeleteKnowledgeBaseResponse, + ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_URL, + ReadKnowledgeBaseRequestParams, + ReadKnowledgeBaseResponse, + Replacements, +} from '@kbn/elastic-assistant-common'; import { API_ERROR } from '../translations'; import { getOptionalRequestParams } from '../helpers'; import { TraceOptions } from '../types'; @@ -52,12 +63,14 @@ export const fetchConnectorExecuteAction = async ({ size, traceOptions, }: FetchConnectorExecuteAction): Promise => { + // TODO add streaming support for gemini with langchain on const isStream = assistantStreamingEnabled && (apiConfig.actionTypeId === '.gen-ai' || - // TODO add streaming support for bedrock with langchain on + apiConfig.actionTypeId === '.bedrock' || + // TODO add streaming support for gemini with langchain on // tracked here: https://github.com/elastic/security-team/issues/7363 - (apiConfig.actionTypeId === '.bedrock' && !isEnabledRAGAlerts && !isEnabledKnowledgeBase)); + (apiConfig.actionTypeId === '.gemini' && !isEnabledRAGAlerts && !isEnabledKnowledgeBase)); const optionalRequestParams = getOptionalRequestParams({ isEnabledRAGAlerts, @@ -179,19 +192,6 @@ export const fetchConnectorExecuteAction = async ({ } }; -export interface GetKnowledgeBaseStatusParams { - http: HttpSetup; - resource?: string; - signal?: AbortSignal | undefined; -} - -export interface GetKnowledgeBaseStatusResponse { - elser_exists: boolean; - esql_exists?: boolean; - index_exists: boolean; - pipeline_exists: boolean; -} - /** * API call for getting the status of the Knowledge Base. Provide * a resource to include the status of that specific resource. @@ -201,37 +201,29 @@ export interface GetKnowledgeBaseStatusResponse { * @param {string} [options.resource] - Resource to get the status of, otherwise status of overall KB * @param {AbortSignal} [options.signal] - AbortSignal * - * @returns {Promise} + * @returns {Promise} */ export const getKnowledgeBaseStatus = async ({ http, resource, signal, -}: GetKnowledgeBaseStatusParams): Promise => { +}: ReadKnowledgeBaseRequestParams & { http: HttpSetup; signal?: AbortSignal | undefined }): Promise< + ReadKnowledgeBaseResponse | IHttpFetchError +> => { try { - const path = `/internal/elastic_assistant/knowledge_base/${resource || ''}`; + const path = ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_URL.replace('{resource?}', resource || ''); const response = await http.fetch(path, { method: 'GET', signal, version: API_VERSIONS.internal.v1, }); - return response as GetKnowledgeBaseStatusResponse; + return response as ReadKnowledgeBaseResponse; } catch (error) { return error as IHttpFetchError; } }; -export interface PostKnowledgeBaseParams { - http: HttpSetup; - resource?: string; - signal?: AbortSignal | undefined; -} - -export interface PostKnowledgeBaseResponse { - success: boolean; -} - /** * API call for setting up the Knowledge Base. Provide a resource to set up a specific resource. * @@ -240,37 +232,30 @@ export interface PostKnowledgeBaseResponse { * @param {string} [options.resource] - Resource to be added to the KB, otherwise sets up the base KB * @param {AbortSignal} [options.signal] - AbortSignal * - * @returns {Promise} + * @returns {Promise} */ export const postKnowledgeBase = async ({ http, resource, signal, -}: PostKnowledgeBaseParams): Promise => { +}: CreateKnowledgeBaseRequestParams & { + http: HttpSetup; + signal?: AbortSignal | undefined; +}): Promise => { try { - const path = `/internal/elastic_assistant/knowledge_base/${resource || ''}`; + const path = ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_URL.replace('{resource?}', resource || ''); const response = await http.fetch(path, { method: 'POST', signal, version: API_VERSIONS.internal.v1, }); - return response as PostKnowledgeBaseResponse; + return response as CreateKnowledgeBaseResponse; } catch (error) { return error as IHttpFetchError; } }; -export interface DeleteKnowledgeBaseParams { - http: HttpSetup; - resource?: string; - signal?: AbortSignal | undefined; -} - -export interface DeleteKnowledgeBaseResponse { - success: boolean; -} - /** * API call for deleting the Knowledge Base. Provide a resource to delete that specific resource. * @@ -285,9 +270,12 @@ export const deleteKnowledgeBase = async ({ http, resource, signal, -}: DeleteKnowledgeBaseParams): Promise => { +}: DeleteKnowledgeBaseRequestParams & { + http: HttpSetup; + signal?: AbortSignal | undefined; +}): Promise => { try { - const path = `/internal/elastic_assistant/knowledge_base/${resource || ''}`; + const path = ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_URL.replace('{resource?}', resource || ''); const response = await http.fetch(path, { method: 'DELETE', signal, 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 5672a48dad0b9..18f2c6be2a863 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/index.tsx @@ -90,6 +90,7 @@ import { clearPresentationData } from '../connectorland/connector_setup/helpers' 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'; export interface Props { conversationTitle?: string; @@ -862,6 +863,9 @@ const AssistantComponent: React.FC = ({ isFlyoutMode /> + + + diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings.test.tsx index 4f745f51a11b7..8278cb1559535 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings.test.tsx @@ -38,7 +38,7 @@ const mockContext = { basePromptContexts: MOCK_QUICK_PROMPTS, setSelectedSettingsTab, http: {}, - modelEvaluatorEnabled: true, + assistantFeatures: { assistantModelEvaluation: true }, selectedSettingsTab: 'CONVERSATIONS_TAB', assistantAvailability: { isAssistantEnabled: true, 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 b6bd193aa8534..f83e6c0d72ee6 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 @@ -86,7 +86,7 @@ export const AssistantSettings: React.FC = React.memo( }) => { const { actionTypeRegistry, - modelEvaluatorEnabled, + assistantFeatures: { assistantModelEvaluation: modelEvaluatorEnabled }, http, toasts, selectedSettingsTab, 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 26cd4340a1435..79a050b11bb27 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 @@ -66,7 +66,7 @@ export const AssistantSettingsManagement: React.FC = React.memo( }) => { const { actionTypeRegistry, - modelEvaluatorEnabled, + assistantFeatures: { assistantModelEvaluation: modelEvaluatorEnabled }, http, selectedSettingsTab, setSelectedSettingsTab, 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 73e9c8ddf3492..08e9fb434b051 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 @@ -171,10 +171,10 @@ describe('useSettingsUpdater', () => { await result.current.saveSettings(); expect(mockHttp.fetch).toHaveBeenCalledWith( - '/api/elastic_assistant/current_user/conversations/_bulk_action', + '/internal/elastic_assistant/current_user/conversations/_bulk_action', { method: 'POST', - version: '2023-10-31', + version: '1', body: '{"delete":{"ids":["1"]}}', } ); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/index.tsx index 7d9cc86941f34..6a74dab81ac47 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/index.tsx @@ -13,7 +13,7 @@ import type { IToasts } from '@kbn/core-notifications-browser'; import { ActionTypeRegistryContract } from '@kbn/triggers-actions-ui-plugin/public'; import { useLocalStorage, useSessionStorage } from 'react-use'; import type { DocLinksStart } from '@kbn/core-doc-links-browser'; -import { defaultAssistantFeatures } from '@kbn/elastic-assistant-common'; +import { AssistantFeatures, defaultAssistantFeatures } from '@kbn/elastic-assistant-common'; import { updatePromptContexts } from './helpers'; import type { PromptContext, @@ -97,6 +97,7 @@ export interface UseAssistantContext { actionTypeRegistry: ActionTypeRegistryContract; alertsIndexPattern: string | undefined; assistantAvailability: AssistantAvailability; + assistantFeatures: AssistantFeatures; assistantStreamingEnabled: boolean; assistantTelemetry?: AssistantTelemetry; augmentMessageCodeBlocks: ( @@ -127,7 +128,6 @@ export interface UseAssistantContext { knowledgeBase: KnowledgeBaseConfig; getLastConversationId: (conversationTitle?: string) => string; promptContexts: Record; - modelEvaluatorEnabled: boolean; nameSpace: string; registerPromptContext: RegisterPromptContext; selectedSettingsTab: SettingsTabs; @@ -276,15 +276,14 @@ export const AssistantProvider: React.FC = ({ ); // Fetch assistant capabilities - const { data: capabilities } = useCapabilities({ http, toasts }); - const { assistantModelEvaluation: modelEvaluatorEnabled } = - capabilities ?? defaultAssistantFeatures; + const { data: assistantFeatures } = useCapabilities({ http, toasts }); const value = useMemo( () => ({ actionTypeRegistry, alertsIndexPattern, assistantAvailability, + assistantFeatures: assistantFeatures ?? defaultAssistantFeatures, assistantTelemetry, augmentMessageCodeBlocks, allQuickPrompts: localStorageQuickPrompts ?? [], @@ -297,7 +296,6 @@ export const AssistantProvider: React.FC = ({ getComments, http, knowledgeBase: { ...DEFAULT_KNOWLEDGE_BASE_SETTINGS, ...localStorageKnowledgeBase }, - modelEvaluatorEnabled, promptContexts, nameSpace, registerPromptContext, @@ -324,6 +322,7 @@ export const AssistantProvider: React.FC = ({ actionTypeRegistry, alertsIndexPattern, assistantAvailability, + assistantFeatures, assistantTelemetry, augmentMessageCodeBlocks, localStorageQuickPrompts, @@ -336,7 +335,6 @@ export const AssistantProvider: React.FC = ({ getComments, http, localStorageKnowledgeBase, - modelEvaluatorEnabled, promptContexts, nameSpace, registerPromptContext, diff --git a/x-pack/packages/kbn-elastic-assistant/impl/content/prompts/system/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/content/prompts/system/translations.ts index 1a8b09f0c2aa1..eecc3b6dea246 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/content/prompts/system/translations.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/content/prompts/system/translations.ts @@ -15,13 +15,6 @@ export const YOU_ARE_A_HELPFUL_EXPERT_ASSISTANT = i18n.translate( } ); -export const USE_THE_FOLLOWING_CONTEXT_TO_ANSWER = i18n.translate( - 'xpack.elasticAssistant.assistant.content.prompts.system.useTheFollowingContextToAnswer', - { - defaultMessage: 'Use the following context to answer questions:', - } -); - export const IF_YOU_DONT_KNOW_THE_ANSWER = i18n.translate( 'xpack.elasticAssistant.assistant.content.prompts.system.ifYouDontKnowTheAnswer', { @@ -37,8 +30,7 @@ export const SUPERHERO_PERSONALITY = i18n.translate( } ); -export const DEFAULT_SYSTEM_PROMPT_NON_I18N = `${YOU_ARE_A_HELPFUL_EXPERT_ASSISTANT} ${IF_YOU_DONT_KNOW_THE_ANSWER} -${USE_THE_FOLLOWING_CONTEXT_TO_ANSWER}`; +export const DEFAULT_SYSTEM_PROMPT_NON_I18N = `${YOU_ARE_A_HELPFUL_EXPERT_ASSISTANT} ${IF_YOU_DONT_KNOW_THE_ANSWER}`; export const DEFAULT_SYSTEM_PROMPT_NAME = i18n.translate( 'xpack.elasticAssistant.assistant.content.prompts.system.defaultSystemPromptName', @@ -48,8 +40,7 @@ export const DEFAULT_SYSTEM_PROMPT_NAME = i18n.translate( ); export const SUPERHERO_SYSTEM_PROMPT_NON_I18N = `${YOU_ARE_A_HELPFUL_EXPERT_ASSISTANT} ${IF_YOU_DONT_KNOW_THE_ANSWER} -${SUPERHERO_PERSONALITY} -${USE_THE_FOLLOWING_CONTEXT_TO_ANSWER}`; +${SUPERHERO_PERSONALITY}`; export const SUPERHERO_SYSTEM_PROMPT_NAME = i18n.translate( 'xpack.elasticAssistant.assistant.content.prompts.system.superheroSystemPromptName', 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/install_knowledge_base_button.tsx new file mode 100644 index 0000000000000..f5a82fd02c55d --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/install_knowledge_base_button.tsx @@ -0,0 +1,64 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useCallback } from 'react'; +import { EuiButton } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +import { useAssistantContext } from '../..'; +import { useSetupKnowledgeBase } from './use_setup_knowledge_base'; +import { useKnowledgeBaseStatus } from './use_knowledge_base_status'; + +const ESQL_RESOURCE = 'esql'; + +/** + * Self-contained component that renders a button to install 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(); + + const { data: kbStatus } = useKnowledgeBaseStatus({ http, resource: ESQL_RESOURCE }); + const { mutate: setupKB, isLoading: isSettingUpKB } = useSetupKnowledgeBase({ http, toasts }); + + const isSetupInProgress = kbStatus?.is_setup_in_progress || isSettingUpKB; + const isSetupComplete = + kbStatus?.elser_exists && + kbStatus?.index_exists && + kbStatus?.pipeline_exists && + kbStatus?.esql_exists; + + const onInstallKnowledgeBase = useCallback(() => { + setupKB(ESQL_RESOURCE); + }, [setupKB]); + + if (!enableKnowledgeBaseByDefault || isSetupComplete) { + return null; + } + + return ( + + {i18n.translate('xpack.elasticAssistant.knowledgeBase.installKnowledgeBaseButton', { + defaultMessage: 'Install Knowledge Base', + })} + + ); +}); + +InstallKnowledgeBaseButton.displayName = 'InstallKnowledgeBaseButton'; 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 20ab3aab4a26f..56f6796ac16fa 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 @@ -13,9 +13,11 @@ import { KnowledgeBaseSettings } from './knowledge_base_settings'; import { TestProviders } from '../mock/test_providers/test_providers'; import { useKnowledgeBaseStatus } from './use_knowledge_base_status'; import { mockSystemPrompts } from '../mock/system_prompt'; +import { defaultAssistantFeatures } from '@kbn/elastic-assistant-common'; const mockUseAssistantContext = { allSystemPrompts: mockSystemPrompts, + assistantFeatures: jest.fn(() => defaultAssistantFeatures), conversations: {}, http: { basePath: { 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 95bf754874966..8c83d1f3403e8 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 @@ -35,7 +35,8 @@ import { useKnowledgeBaseStatus } from './use_knowledge_base_status'; import { useSetupKnowledgeBase } from './use_setup_knowledge_base'; const ESQL_RESOURCE = 'esql'; -const KNOWLEDGE_BASE_INDEX_PATTERN = '.kibana-elastic-ai-assistant-kb'; +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 { knowledgeBase: KnowledgeBaseConfig; @@ -47,7 +48,10 @@ interface Props { */ export const KnowledgeBaseSettings: React.FC = React.memo( ({ knowledgeBase, setUpdatedKnowledgeBaseSettings }) => { - const { http } = useAssistantContext(); + const { + assistantFeatures: { assistantKnowledgeBaseByDefault: enableKnowledgeBaseByDefault }, + http, + } = useAssistantContext(); const { data: kbStatus, isLoading, @@ -60,14 +64,18 @@ export const KnowledgeBaseSettings: React.FC = React.memo( const isElserEnabled = kbStatus?.elser_exists ?? false; const isKnowledgeBaseEnabled = (kbStatus?.index_exists && kbStatus?.pipeline_exists) ?? false; const isESQLEnabled = kbStatus?.esql_exists ?? false; + const isSetupInProgress = kbStatus?.is_setup_in_progress ?? false; // Resource availability state - const isLoadingKb = isLoading || isFetching || isSettingUpKB || isDeletingUpKB; + 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 = !kbStatus?.elser_exists && !knowledgeBase.isEnabledKnowledgeBase; + const isSwitchDisabled = enableKnowledgeBaseByDefault + ? false + : !kbStatus?.elser_exists && !knowledgeBase.isEnabledKnowledgeBase; // Calculated health state for EuiHealth component const elserHealth = isElserEnabled ? 'success' : 'subdued'; @@ -84,12 +92,18 @@ export const KnowledgeBaseSettings: React.FC = React.memo( isEnabledKnowledgeBase: event.target.checked, }); - // If enabling and ELSER exists, try to set up automatically - if (event.target.checked && kbStatus?.elser_exists) { + // 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); } }, - [kbStatus?.elser_exists, knowledgeBase, setUpdatedKnowledgeBaseSettings, setupKB] + [ + enableKnowledgeBaseByDefault, + kbStatus?.elser_exists, + knowledgeBase, + setUpdatedKnowledgeBaseSettings, + setupKB, + ] ); const isEnabledKnowledgeBaseSwitch = useMemo(() => { @@ -149,7 +163,11 @@ export const KnowledgeBaseSettings: React.FC = React.memo( const knowledgeBaseDescription = useMemo(() => { return isKnowledgeBaseEnabled ? ( - {i18n.KNOWLEDGE_BASE_DESCRIPTION_INSTALLED(KNOWLEDGE_BASE_INDEX_PATTERN)}{' '} + {i18n.KNOWLEDGE_BASE_DESCRIPTION_INSTALLED( + enableKnowledgeBaseByDefault + ? KNOWLEDGE_BASE_INDEX_PATTERN + : KNOWLEDGE_BASE_INDEX_PATTERN_OLD + )}{' '} {knowledgeBaseActionButton} ) : ( @@ -157,7 +175,7 @@ export const KnowledgeBaseSettings: React.FC = React.memo( {i18n.KNOWLEDGE_BASE_DESCRIPTION} {knowledgeBaseActionButton} ); - }, [isKnowledgeBaseEnabled, knowledgeBaseActionButton]); + }, [enableKnowledgeBaseByDefault, isKnowledgeBaseEnabled, knowledgeBaseActionButton]); ////////////////////////////////////////////////////////////////////////////////////////// // ESQL Resource diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/use_knowledge_base_status.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/use_knowledge_base_status.tsx index 7ec7d227f9ef8..c03eb31581e42 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/use_knowledge_base_status.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/use_knowledge_base_status.tsx @@ -11,6 +11,7 @@ import type { HttpSetup, IHttpFetchError, ResponseErrorBody } from '@kbn/core-ht import type { IToasts } from '@kbn/core-notifications-browser'; import { i18n } from '@kbn/i18n'; import { useCallback } from 'react'; +import { ReadKnowledgeBaseResponse } from '@kbn/elastic-assistant-common'; import { getKnowledgeBaseStatus } from '../assistant/api'; const KNOWLEDGE_BASE_STATUS_QUERY_KEY = ['elastic-assistant', 'knowledge-base-status']; @@ -21,13 +22,6 @@ export interface UseKnowledgeBaseStatusParams { toasts?: IToasts; } -export interface GetKnowledgeBaseStatusResponse { - elser_exists: boolean; - esql_exists?: boolean; - index_exists: boolean; - pipeline_exists: boolean; -} - /** * Hook for getting the status of the Knowledge Base. Provide a resource name to include * the status for that specific resource within the KB. @@ -42,10 +36,7 @@ export const useKnowledgeBaseStatus = ({ http, resource, toasts, -}: UseKnowledgeBaseStatusParams): UseQueryResult< - GetKnowledgeBaseStatusResponse, - IHttpFetchError -> => { +}: UseKnowledgeBaseStatusParams): UseQueryResult => { return useQuery( KNOWLEDGE_BASE_STATUS_QUERY_KEY, async ({ signal }) => { diff --git a/x-pack/packages/kbn-elastic-assistant/index.ts b/x-pack/packages/kbn-elastic-assistant/index.ts index 56fb74af3aba4..df0ba1e8db0f9 100644 --- a/x-pack/packages/kbn-elastic-assistant/index.ts +++ b/x-pack/packages/kbn-elastic-assistant/index.ts @@ -145,13 +145,6 @@ export type { PromptContextTemplate } from './impl/assistant/prompt_context/type */ export type { QuickPrompt } from './impl/assistant/quick_prompts/types'; -/** - * Knowledge Base API Responses - */ -export type { DeleteKnowledgeBaseResponse } from './impl/assistant/api'; -export type { GetKnowledgeBaseStatusResponse } from './impl/assistant/api'; -export type { PostKnowledgeBaseResponse } from './impl/assistant/api'; - export { useFetchCurrentUserConversations } from './impl/assistant/api/conversations/use_fetch_current_user_conversations'; export * from './impl/assistant/api/conversations/bulk_update_actions_conversations'; export { getConversationById } from './impl/assistant/api/conversations/conversations'; diff --git a/x-pack/packages/kbn-langchain/README.md b/x-pack/packages/kbn-langchain/README.md new file mode 100644 index 0000000000000..71b123bb367ee --- /dev/null +++ b/x-pack/packages/kbn-langchain/README.md @@ -0,0 +1,5 @@ +# @kbn/langchain + +Contains LangChain language models to be used with Kibana connectors + +The package does not expose `index.ts` at its root, instead there's a `server` directory you should deep-import from. \ No newline at end of file diff --git a/x-pack/packages/kbn-langchain/jest.config.js b/x-pack/packages/kbn-langchain/jest.config.js new file mode 100644 index 0000000000000..f436e6a9edbe6 --- /dev/null +++ b/x-pack/packages/kbn-langchain/jest.config.js @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +module.exports = { + coverageDirectory: '/target/kibana-coverage/jest/x-pack/packages/kbn_langchain', + coverageReporters: ['text', 'html'], + collectCoverageFrom: [ + '/x-pack/packages/kbn-langchain/server/**/*.{ts}', + '!/x-pack/packages/kbn-langchain/server/{__test__,__snapshots__,__examples__,*mock*,tests,test_helpers,integration_tests,types}/**/*', + '!/x-pack/packages/kbn-langchain/server/*mock*.{ts}', + '!/x-pack/packages/kbn-langchain/server/*.test.{ts}', + '!/x-pack/packages/kbn-langchain/server/*.d.ts', + '!/x-pack/packages/kbn-langchain/server/*.config.ts', + ], + preset: '@kbn/test', + rootDir: '../../..', + roots: ['/x-pack/packages/kbn-langchain'], +}; diff --git a/x-pack/packages/kbn-langchain/kibana.jsonc b/x-pack/packages/kbn-langchain/kibana.jsonc new file mode 100644 index 0000000000000..5ef91bd2c8e6a --- /dev/null +++ b/x-pack/packages/kbn-langchain/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-server", + "id": "@kbn/langchain", + "owner": "@elastic/security-generative-ai" +} diff --git a/x-pack/packages/kbn-langchain/package.json b/x-pack/packages/kbn-langchain/package.json new file mode 100644 index 0000000000000..fd57d74aff17c --- /dev/null +++ b/x-pack/packages/kbn-langchain/package.json @@ -0,0 +1,7 @@ +{ + "name": "@kbn/langchain", + "private": true, + "version": "1.0.0", + "license": "Elastic License 2.0", + "sideEffects": false +} diff --git a/x-pack/packages/kbn-langchain/server/index.ts b/x-pack/packages/kbn-langchain/server/index.ts new file mode 100644 index 0000000000000..12c32c86563a8 --- /dev/null +++ b/x-pack/packages/kbn-langchain/server/index.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ActionsClientChatOpenAI } from './language_models/chat_openai'; +import { ActionsClientLlm } from './language_models/llm'; +import { ActionsClientSimpleChatModel } from './language_models/simple_chat_model'; +import { parseBedrockStream } from './utils/bedrock'; +import { getDefaultArguments } from './language_models/constants'; + +export { + parseBedrockStream, + getDefaultArguments, + ActionsClientChatOpenAI, + ActionsClientLlm, + ActionsClientSimpleChatModel, +}; diff --git a/x-pack/packages/kbn-langchain/server/language_models/chat_openai.test.ts b/x-pack/packages/kbn-langchain/server/language_models/chat_openai.test.ts new file mode 100644 index 0000000000000..5c6d389a4ccc4 --- /dev/null +++ b/x-pack/packages/kbn-langchain/server/language_models/chat_openai.test.ts @@ -0,0 +1,204 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type OpenAI from 'openai'; +import { Stream } from 'openai/streaming'; +import type { PluginStartContract as ActionsPluginStart } from '@kbn/actions-plugin/server'; +import { loggerMock } from '@kbn/logging-mocks'; + +import { ActionsClientChatOpenAI, ActionsClientChatOpenAIParams } from './chat_openai'; +import { mockActionResponse, mockChatCompletion } from './mocks'; + +const connectorId = 'mock-connector-id'; + +const mockExecute = jest.fn(); + +const mockLogger = loggerMock.create(); + +const mockActions = { + getActionsClientWithRequest: jest.fn().mockImplementation(() => ({ + execute: mockExecute, + })), +} as unknown as ActionsPluginStart; +const chunk = { + object: 'chat.completion.chunk', + choices: [ + { + delta: { + content: 'Single.', + }, + }, + ], +}; + +export async function* asyncGenerator() { + // Mock implementation + yield chunk; +} +const mockStreamExecute = jest.fn(); +const mockStreamActions = { + getActionsClientWithRequest: jest.fn().mockImplementation(() => ({ + execute: mockStreamExecute, + })), +} as unknown as ActionsPluginStart; + +const prompt = 'Do you know my name?'; + +const { signal } = new AbortController(); + +const mockRequest = { + params: { connectorId }, + body: { + message: prompt, + subAction: 'invokeAI', + isEnabledKnowledgeBase: true, + }, +} as ActionsClientChatOpenAIParams['request']; + +const defaultArgs = { + actions: mockActions, + connectorId, + logger: mockLogger, + request: mockRequest, + streaming: false, + signal, + timeout: 999999, + temperature: 0.2, +}; + +describe('ActionsClientChatOpenAI', () => { + beforeEach(() => { + jest.clearAllMocks(); + mockExecute.mockImplementation(() => ({ + data: mockChatCompletion, + status: 'ok', + })); + }); + + describe('_llmType', () => { + it('returns the expected LLM type', () => { + const actionsClientChatOpenAI = new ActionsClientChatOpenAI(defaultArgs); + + expect(actionsClientChatOpenAI._llmType()).toEqual('ActionsClientChatOpenAI'); + }); + + it('returns the expected LLM type when overridden', () => { + const actionsClientChatOpenAI = new ActionsClientChatOpenAI({ + ...defaultArgs, + llmType: 'special-llm-type', + }); + + expect(actionsClientChatOpenAI._llmType()).toEqual('special-llm-type'); + }); + }); + + describe('completionWithRetry streaming: true', () => { + beforeEach(() => { + jest.clearAllMocks(); + mockStreamExecute.mockImplementation(() => ({ + data: { + consumerStream: asyncGenerator() as unknown as Stream, + tokenCountStream: asyncGenerator() as unknown as Stream, + }, + status: 'ok', + })); + }); + const defaultStreamingArgs: OpenAI.ChatCompletionCreateParamsStreaming = { + messages: [{ content: prompt, role: 'user' }], + stream: true, + model: 'gpt-4', + n: 99, + stop: ['a stop sequence'], + functions: [jest.fn()], + }; + it('returns the expected data', async () => { + const actionsClientChatOpenAI = new ActionsClientChatOpenAI({ + ...defaultArgs, + streaming: true, + actions: mockStreamActions, + }); + + const result: AsyncIterable = + await actionsClientChatOpenAI.completionWithRetry(defaultStreamingArgs); + expect(mockStreamExecute).toHaveBeenCalledWith({ + actionId: connectorId, + params: { + subActionParams: { + model: 'gpt-4', + messages: [{ role: 'user', content: 'Do you know my name?' }], + signal, + timeout: 999999, + n: defaultStreamingArgs.n, + stop: defaultStreamingArgs.stop, + functions: defaultStreamingArgs.functions, + temperature: 0.2, + }, + subAction: 'invokeAsyncIterator', + }, + signal, + }); + expect(result).toEqual(asyncGenerator()); + }); + }); + + describe('completionWithRetry streaming: false', () => { + const defaultNonStreamingArgs: OpenAI.ChatCompletionCreateParamsNonStreaming = { + messages: [{ content: prompt, role: 'user' }], + stream: false, + model: 'gpt-4', + }; + it('returns the expected data', async () => { + const actionsClientChatOpenAI = new ActionsClientChatOpenAI(defaultArgs); + + const result: OpenAI.ChatCompletion = await actionsClientChatOpenAI.completionWithRetry( + defaultNonStreamingArgs + ); + expect(mockExecute).toHaveBeenCalledWith({ + actionId: connectorId, + params: { + subActionParams: { + body: '{"temperature":0.2,"model":"gpt-4","messages":[{"role":"user","content":"Do you know my name?"}]}', + signal, + timeout: 999999, + }, + subAction: 'run', + }, + signal, + }); + expect(result.choices[0].message.content).toEqual(mockActionResponse.message); + }); + + it('rejects with the expected error when the action result status is error', async () => { + const hasErrorStatus = jest.fn().mockImplementation(() => ({ + message: 'action-result-message', + serviceMessage: 'action-result-service-message', + status: 'error', // <-- error status + })); + + const badActions = { + getActionsClientWithRequest: jest.fn().mockImplementation(() => ({ + execute: hasErrorStatus, + })), + } as unknown as ActionsPluginStart; + + const actionsClientChatOpenAI = new ActionsClientChatOpenAI({ + ...defaultArgs, + actions: badActions, + }); + + expect(actionsClientChatOpenAI.completionWithRetry(defaultNonStreamingArgs)) + .rejects.toThrowError( + 'ActionsClientChatOpenAI: action result status is error: action-result-message - action-result-service-message' + ) + .catch(() => { + /* ...handle/report the error (or just suppress it, if that's appropriate + [which it sometimes, though rarely, is])... + */ + }); + }); + }); +}); diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/language_models/chat_openai.ts b/x-pack/packages/kbn-langchain/server/language_models/chat_openai.ts similarity index 66% rename from x-pack/packages/kbn-elastic-assistant-common/impl/language_models/chat_openai.ts rename to x-pack/packages/kbn-langchain/server/language_models/chat_openai.ts index b334ae3a0928a..7675e2442e598 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/language_models/chat_openai.ts +++ b/x-pack/packages/kbn-langchain/server/language_models/chat_openai.ts @@ -12,18 +12,13 @@ import { get } from 'lodash/fp'; import { ChatOpenAI } from '@langchain/openai'; import { Stream } from 'openai/streaming'; -import { - ChatCompletion, - ChatCompletionChunk, - ChatCompletionCreateParamsStreaming, - ChatCompletionCreateParamsNonStreaming, -} from 'openai/resources/chat/completions'; +import type OpenAI from 'openai'; import { DEFAULT_OPEN_AI_MODEL, DEFAULT_TIMEOUT } from './constants'; -import { InvokeAIActionParamsSchema } from './types'; +import { InvokeAIActionParamsSchema, RunActionParamsSchema } from './types'; const LLM_TYPE = 'ActionsClientChatOpenAI'; -interface ActionsClientChatOpenAIParams { +export interface ActionsClientChatOpenAIParams { actions: ActionsPluginStart; connectorId: string; llmType?: string; @@ -47,15 +42,14 @@ interface ActionsClientChatOpenAIParams { * and iterates over the chunks to form the response. */ export class ActionsClientChatOpenAI extends ChatOpenAI { - // set streaming to true always - streaming = true; + streaming: boolean; // Local `llmType` as it can change and needs to be accessed by abstract `_llmType()` method // Not using getter as `this._llmType()` is called in the constructor via `super({})` protected llmType: string; // ChatOpenAI class needs these, but they do not matter as we override the openai client with the actions client azureOpenAIApiKey = ''; openAIApiKey = ''; - model?: string; + model: string; #temperature?: number; // Kibana variables @@ -78,12 +72,13 @@ export class ActionsClientChatOpenAI extends ChatOpenAI { maxRetries, model, signal, + streaming = true, temperature, timeout, }: ActionsClientChatOpenAIParams) { super({ maxRetries, - streaming: true, + streaming, // matters only for the LangSmith logs (Metadata > Invocation Params), which are misleading if this is not set modelName: model ?? DEFAULT_OPEN_AI_MODEL, // these have to be initialized, but are not actually used since we override the openai client with the actions client @@ -102,9 +97,9 @@ export class ActionsClientChatOpenAI extends ChatOpenAI { this.#request = request; this.#timeout = timeout; this.#actionResultData = ''; - this.streaming = true; + this.streaming = streaming; this.#signal = signal; - this.model = model; + this.model = model ?? DEFAULT_OPEN_AI_MODEL; // to be passed to the actions client this.#temperature = temperature; // matters only for LangSmith logs (Metadata > Invocation Params) @@ -128,20 +123,18 @@ export class ActionsClientChatOpenAI extends ChatOpenAI { } async completionWithRetry( - request: ChatCompletionCreateParamsStreaming - ): Promise>; + request: OpenAI.ChatCompletionCreateParamsStreaming + ): Promise>; async completionWithRetry( - request: ChatCompletionCreateParamsNonStreaming - ): Promise; + request: OpenAI.ChatCompletionCreateParamsNonStreaming + ): Promise; async completionWithRetry( - completionRequest: ChatCompletionCreateParamsStreaming | ChatCompletionCreateParamsNonStreaming - ): Promise | ChatCompletion> { - if (!completionRequest.stream) { - // fallback for typescript, should never be hit - return super.completionWithRetry(completionRequest); - } + completionRequest: + | OpenAI.ChatCompletionCreateParamsStreaming + | OpenAI.ChatCompletionCreateParamsNonStreaming + ): Promise | OpenAI.ChatCompletion> { return this.caller.call(async () => { const requestBody = this.formatRequestForActionsClient(completionRequest); this.#logger.debug( @@ -159,10 +152,17 @@ export class ActionsClientChatOpenAI extends ChatOpenAI { throw new Error(`${LLM_TYPE}: ${actionResult?.message} - ${actionResult?.serviceMessage}`); } + if (!this.streaming) { + // typecasting as the `run` subaction returns the OpenAI.ChatCompletion directly from OpenAI + const chatCompletion = get('data', actionResult) as OpenAI.ChatCompletion; + + return chatCompletion; + } + // cast typing as this is the contract of the actions client const result = get('data', actionResult) as { - consumerStream: Stream; - tokenCountStream: Stream; + consumerStream: Stream; + tokenCountStream: Stream; }; if (result.consumerStream == null) { @@ -172,39 +172,47 @@ export class ActionsClientChatOpenAI extends ChatOpenAI { return result.consumerStream; }); } - formatRequestForActionsClient(completionRequest: ChatCompletionCreateParamsStreaming): { + formatRequestForActionsClient( + completionRequest: + | OpenAI.ChatCompletionCreateParamsNonStreaming + | OpenAI.ChatCompletionCreateParamsStreaming + ): { actionId: string; params: { - subActionParams: InvokeAIActionParamsSchema; + subActionParams: InvokeAIActionParamsSchema | RunActionParamsSchema; subAction: string; }; signal?: AbortSignal; } { + const body = { + temperature: this.#temperature, + // possible client model override + // security sends this from connectors, it is only missing from preconfigured connectors + // this should be undefined otherwise so the connector handles the model (stack_connector has access to preconfigured connector model values) + model: this.model, + // ensure we take the messages from the completion request, not the client request + n: completionRequest.n, + stop: completionRequest.stop, + functions: completionRequest.functions, + messages: completionRequest.messages.map((message) => ({ + role: message.role, + content: message.content ?? '', + ...('name' in message ? { name: message?.name } : {}), + ...('function_call' in message ? { function_call: message?.function_call } : {}), + ...('tool_calls' in message ? { tool_calls: message?.tool_calls } : {}), + ...('tool_call_id' in message ? { tool_call_id: message?.tool_call_id } : {}), + })), + }; // create a new connector request body with the assistant message: return { actionId: this.#connectorId, params: { - // stream must already be true here - // langchain expects stream to be of type AsyncIterator - subAction: 'invokeAsyncIterator', + // langchain expects stream to be of type AsyncIterator + // for non-stream, use `run` instead of `invokeAI` in order to get the entire OpenAI.ChatCompletion response, + // which may contain non-content messages like functions + subAction: completionRequest.stream ? 'invokeAsyncIterator' : 'run', subActionParams: { - temperature: this.#temperature, - // possible client model override - // security sends this from connectors, it is only missing from preconfigured connectors - // this should be undefined otherwise so the connector handles the model (stack_connector has access to preconfigured connector model values) - model: this.model, - // ensure we take the messages from the completion request, not the client request - n: completionRequest.n, - stop: completionRequest.stop, - functions: completionRequest.functions, - messages: completionRequest.messages.map((message) => ({ - role: message.role, - content: message.content ?? '', - ...('name' in message ? { name: message?.name } : {}), - ...('function_call' in message ? { function_call: message?.function_call } : {}), - ...('tool_calls' in message ? { tool_calls: message?.tool_calls } : {}), - ...('tool_call_id' in message ? { tool_call_id: message?.tool_call_id } : {}), - })), + ...(completionRequest.stream ? body : { body: JSON.stringify(body) }), signal: this.#signal, // This timeout is large because LangChain prompts can be complicated and take a long time timeout: this.#timeout ?? DEFAULT_TIMEOUT, diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/language_models/constants.ts b/x-pack/packages/kbn-langchain/server/language_models/constants.ts similarity index 100% rename from x-pack/packages/kbn-elastic-assistant-common/impl/language_models/constants.ts rename to x-pack/packages/kbn-langchain/server/language_models/constants.ts diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/language_models/helpers.test.ts b/x-pack/packages/kbn-langchain/server/language_models/helpers.test.ts similarity index 88% rename from x-pack/packages/kbn-elastic-assistant-common/impl/language_models/helpers.test.ts rename to x-pack/packages/kbn-langchain/server/language_models/helpers.test.ts index c98300aa64c78..1ed4233281d2e 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/language_models/helpers.test.ts +++ b/x-pack/packages/kbn-langchain/server/language_models/helpers.test.ts @@ -5,12 +5,11 @@ * 2.0. */ -import { Message } from '../schemas'; import { getMessageContentAndRole } from './helpers'; describe('helpers', () => { describe('getMessageContentAndRole', () => { - const testCases: Array<[string, Pick]> = [ + const testCases: Array<[string, { content: string; role: string }]> = [ ['Prompt 1', { content: 'Prompt 1', role: 'user' }], ['Prompt 2', { content: 'Prompt 2', role: 'user' }], ['', { content: '', role: 'user' }], diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/language_models/helpers.ts b/x-pack/packages/kbn-langchain/server/language_models/helpers.ts similarity index 68% rename from x-pack/packages/kbn-elastic-assistant-common/impl/language_models/helpers.ts rename to x-pack/packages/kbn-langchain/server/language_models/helpers.ts index 4688ab122c4f3..3041f8296d68f 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/language_models/helpers.ts +++ b/x-pack/packages/kbn-langchain/server/language_models/helpers.ts @@ -5,9 +5,7 @@ * 2.0. */ -import { Message } from '../schemas'; - -export const getMessageContentAndRole = (prompt: string): Pick => ({ +export const getMessageContentAndRole = (prompt: string): { content: string; role: string } => ({ content: prompt, role: 'user', }); diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/language_models/index.ts b/x-pack/packages/kbn-langchain/server/language_models/index.ts similarity index 83% rename from x-pack/packages/kbn-elastic-assistant-common/impl/language_models/index.ts rename to x-pack/packages/kbn-langchain/server/language_models/index.ts index 791ba33b18a18..fcde4156e0d02 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/language_models/index.ts +++ b/x-pack/packages/kbn-langchain/server/language_models/index.ts @@ -7,3 +7,4 @@ export { ActionsClientChatOpenAI } from './chat_openai'; export { ActionsClientLlm } from './llm'; +export { ActionsClientSimpleChatModel } from './simple_chat_model'; diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/language_models/llm.test.ts b/x-pack/packages/kbn-langchain/server/language_models/llm.test.ts similarity index 95% rename from x-pack/packages/kbn-elastic-assistant-common/impl/language_models/llm.test.ts rename to x-pack/packages/kbn-langchain/server/language_models/llm.test.ts index 7ef6d4a15db28..e0f7b764b625a 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/language_models/llm.test.ts +++ b/x-pack/packages/kbn-langchain/server/language_models/llm.test.ts @@ -10,7 +10,7 @@ import type { PluginStartContract as ActionsPluginStart } from '@kbn/actions-plu import { loggerMock } from '@kbn/logging-mocks'; import { ActionsClientLlm } from './llm'; -import { mockActionResponse } from '../mock/mock_action_response'; +import { mockActionResponse } from './mocks'; const connectorId = 'mock-connector-id'; @@ -117,7 +117,7 @@ describe('ActionsClientLlm', () => { request: mockRequest, }); - expect(actionsClientLlm._call(prompt)).rejects.toThrowError( + await expect(actionsClientLlm._call(prompt)).rejects.toThrowError( 'ActionsClientLlm: action result status is error: action-result-message - action-result-service-message' ); }); @@ -137,7 +137,7 @@ describe('ActionsClientLlm', () => { request: mockRequest, }); - expect(actionsClientLlm._call(prompt)).rejects.toThrowError( + await expect(actionsClientLlm._call(prompt)).rejects.toThrowError( 'ActionsClientLlm: content should be a string, but it had an unexpected type: number' ); }); diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/language_models/llm.ts b/x-pack/packages/kbn-langchain/server/language_models/llm.ts similarity index 100% rename from x-pack/packages/kbn-elastic-assistant-common/impl/language_models/llm.ts rename to x-pack/packages/kbn-langchain/server/language_models/llm.ts diff --git a/x-pack/packages/kbn-langchain/server/language_models/mocks/index.ts b/x-pack/packages/kbn-langchain/server/language_models/mocks/index.ts new file mode 100644 index 0000000000000..f40bafca1a469 --- /dev/null +++ b/x-pack/packages/kbn-langchain/server/language_models/mocks/index.ts @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type OpenAI from 'openai'; + +export const mockActionResponse = { + message: 'Yes, your name is Andrew. How can I assist you further, Andrew?', + usage: { prompt_tokens: 4, completion_tokens: 10, total_tokens: 14 }, +}; + +export const mockChatCompletion: OpenAI.ChatCompletion = { + id: 'abc123', + choices: [ + { + index: 0, + message: { + role: 'assistant', + content: 'Yes, your name is Andrew. How can I assist you further, Andrew?', + }, + finish_reason: 'stop', + logprobs: null, + }, + ], + created: 1684572400, // Unix timestamp example: May 20, 2023 + model: 'gpt-4', + object: 'chat.completion', + system_fingerprint: 'fingerprint123', + usage: { + prompt_tokens: 10, + completion_tokens: 15, + total_tokens: 25, + }, +}; diff --git a/x-pack/packages/kbn-langchain/server/language_models/simple_chat_model.test.ts b/x-pack/packages/kbn-langchain/server/language_models/simple_chat_model.test.ts new file mode 100644 index 0000000000000..6a11466f9faa0 --- /dev/null +++ b/x-pack/packages/kbn-langchain/server/language_models/simple_chat_model.test.ts @@ -0,0 +1,299 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { PassThrough } from 'stream'; +import type { PluginStartContract as ActionsPluginStart } from '@kbn/actions-plugin/server'; +import { loggerMock } from '@kbn/logging-mocks'; + +import { ActionsClientSimpleChatModel, CustomChatModelInput } from './simple_chat_model'; +import { mockActionResponse } from './mocks'; +import { BaseMessage } from '@langchain/core/messages'; +import { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager'; +import { parseBedrockStream } from '../utils/bedrock'; + +const connectorId = 'mock-connector-id'; + +const mockExecute = jest.fn(); + +const mockLogger = loggerMock.create(); + +const mockActions = { + getActionsClientWithRequest: jest.fn().mockImplementation(() => ({ + execute: mockExecute, + })), +} as unknown as ActionsPluginStart; + +const mockStreamExecute = jest.fn().mockImplementation(() => ({ + data: new PassThrough(), + status: 'ok', +})); +const mockStreamActions = { + getActionsClientWithRequest: jest.fn().mockImplementation(() => ({ + execute: mockStreamExecute, + })), +} as unknown as ActionsPluginStart; + +const prompt = 'Do you know my name?'; +const callMessages = [ + { + lc_serializable: true, + lc_kwargs: { + content: 'Answer the following questions truthfully and as best you can.', + additional_kwargs: {}, + response_metadata: {}, + }, + lc_namespace: ['langchain_core', 'messages'], + content: 'Answer the following questions truthfully and as best you can.', + name: undefined, + additional_kwargs: {}, + response_metadata: {}, + _getType: () => 'system', + }, + { + lc_serializable: true, + lc_kwargs: { + content: 'Question: Do you know my name?\n\n', + additional_kwargs: {}, + response_metadata: {}, + }, + lc_namespace: ['langchain_core', 'messages'], + content: 'Question: Do you know my name?\n\n', + name: undefined, + additional_kwargs: {}, + response_metadata: {}, + _getType: () => 'human', + }, +] as unknown as BaseMessage[]; + +const callOptions = { + stop: ['\n'], +}; +const handleLLMNewToken = jest.fn(); +const callRunManager = { + handleLLMNewToken, +} as unknown as CallbackManagerForLLMRun; + +const mockRequest: CustomChatModelInput['request'] = { + params: { connectorId }, + body: { + message: prompt, + subAction: 'invokeAI', + isEnabledKnowledgeBase: true, + }, +} as CustomChatModelInput['request']; + +const defaultArgs = { + actions: mockActions, + connectorId, + logger: mockLogger, + request: mockRequest, + streaming: false, +}; +jest.mock('../utils/bedrock'); + +describe('ActionsClientSimpleChatModel', () => { + beforeEach(() => { + jest.clearAllMocks(); + mockExecute.mockImplementation(() => ({ + data: mockActionResponse, + status: 'ok', + })); + }); + + describe('getActionResultData', () => { + it('returns the expected data', async () => { + const actionsClientSimpleChatModel = new ActionsClientSimpleChatModel(defaultArgs); + + const result = await actionsClientSimpleChatModel._call( + callMessages, + callOptions, + callRunManager + ); + + expect(result).toEqual(mockActionResponse.message); + }); + }); + + describe('_llmType', () => { + it('returns the expected LLM type', () => { + const actionsClientSimpleChatModel = new ActionsClientSimpleChatModel(defaultArgs); + + expect(actionsClientSimpleChatModel._llmType()).toEqual('ActionsClientSimpleChatModel'); + }); + + it('returns the expected LLM type when overridden', () => { + const actionsClientSimpleChatModel = new ActionsClientSimpleChatModel({ + ...defaultArgs, + llmType: 'special-llm-type', + }); + + expect(actionsClientSimpleChatModel._llmType()).toEqual('special-llm-type'); + }); + }); + + describe('_call streaming: false', () => { + it('returns the expected content when _call is invoked', async () => { + const actionsClientSimpleChatModel = new ActionsClientSimpleChatModel(defaultArgs); + + const result = await actionsClientSimpleChatModel._call( + callMessages, + callOptions, + callRunManager + ); + const subAction = mockExecute.mock.calls[0][0].params.subAction; + expect(subAction).toEqual('invokeAI'); + + expect(result).toEqual(mockActionResponse.message); + }); + + it('rejects with the expected error when the action result status is error', async () => { + const hasErrorStatus = jest.fn().mockImplementation(() => ({ + message: 'action-result-message', + serviceMessage: 'action-result-service-message', + status: 'error', // <-- error status + })); + + const badActions = { + getActionsClientWithRequest: jest.fn().mockImplementation(() => ({ + execute: hasErrorStatus, + })), + } as unknown as ActionsPluginStart; + + const actionsClientSimpleChatModel = new ActionsClientSimpleChatModel({ + ...defaultArgs, + actions: badActions, + }); + + await expect( + actionsClientSimpleChatModel._call(callMessages, callOptions, callRunManager) + ).rejects.toThrowError( + 'ActionsClientSimpleChatModel: action result status is error: action-result-message - action-result-service-message' + ); + }); + + it('rejects with the expected error the message has invalid content', async () => { + const invalidContent = { message: 1234 }; + + mockExecute.mockImplementation(() => ({ + data: invalidContent, + status: 'ok', + })); + + const actionsClientSimpleChatModel = new ActionsClientSimpleChatModel(defaultArgs); + + await expect( + actionsClientSimpleChatModel._call(callMessages, callOptions, callRunManager) + ).rejects.toThrowError( + 'ActionsClientSimpleChatModel: content should be a string, but it had an unexpected type: number' + ); + }); + + it('throws multimodal error', async () => { + const invalidContent = { message: 1234 }; + + mockExecute.mockImplementation(() => ({ + data: invalidContent, + status: 'ok', + })); + + const actionsClientSimpleChatModel = new ActionsClientSimpleChatModel(defaultArgs); + + await expect( + actionsClientSimpleChatModel._call( + // @ts-ignore + [{ ...callMessages[0], content: null }], + callOptions, + callRunManager + ) + ).rejects.toThrowError('Multimodal messages are not supported'); + }); + }); + + describe('_call streaming: true', () => { + beforeEach(() => { + (parseBedrockStream as jest.Mock).mockResolvedValue(mockActionResponse.message); + }); + it('returns the expected content when _call is invoked with streaming and llmType is Bedrock', async () => { + const actionsClientSimpleChatModel = new ActionsClientSimpleChatModel({ + ...defaultArgs, + actions: mockStreamActions, + llmType: 'bedrock', + streaming: true, + }); + + const result = await actionsClientSimpleChatModel._call( + callMessages, + callOptions, + callRunManager + ); + const subAction = mockStreamExecute.mock.calls[0][0].params.subAction; + expect(subAction).toEqual('invokeStream'); + + expect(result).toEqual(mockActionResponse.message); + }); + it('returns the expected content when _call is invoked with streaming and llmType is Gemini', async () => { + const actionsClientSimpleChatModel = new ActionsClientSimpleChatModel({ + ...defaultArgs, + actions: mockActions, + llmType: 'gemini', + streaming: true, + }); + + const result = await actionsClientSimpleChatModel._call( + callMessages, + callOptions, + callRunManager + ); + const subAction = mockExecute.mock.calls[0][0].params.subAction; + expect(subAction).toEqual('invokeAI'); + + expect(result).toEqual(mockActionResponse.message); + }); + it('does not call handleLLMNewToken until the final answer', async () => { + (parseBedrockStream as jest.Mock).mockImplementation((_1, _2, _3, handleToken) => { + handleToken('token1'); + handleToken('token2'); + handleToken('token3'); + handleToken('token4'); + handleToken('token5'); + handleToken(`"action":`); + handleToken(`"Final Answer"`); + handleToken(`, "action_input": "`); + handleToken('token6'); + }); + const actionsClientSimpleChatModel = new ActionsClientSimpleChatModel({ + ...defaultArgs, + actions: mockStreamActions, + llmType: 'bedrock', + streaming: true, + }); + await actionsClientSimpleChatModel._call(callMessages, callOptions, callRunManager); + expect(handleLLMNewToken).toHaveBeenCalledTimes(1); + expect(handleLLMNewToken).toHaveBeenCalledWith('token6'); + }); + it('does not call handleLLMNewToken after the final output ends', async () => { + (parseBedrockStream as jest.Mock).mockImplementation((_1, _2, _3, handleToken) => { + handleToken('token5'); + handleToken(`"action":`); + handleToken(`"Final Answer"`); + handleToken(`, "action_input": "`); + handleToken('token6'); + handleToken('"'); + handleToken('token7'); + }); + const actionsClientSimpleChatModel = new ActionsClientSimpleChatModel({ + ...defaultArgs, + actions: mockStreamActions, + llmType: 'bedrock', + streaming: true, + }); + await actionsClientSimpleChatModel._call(callMessages, callOptions, callRunManager); + expect(handleLLMNewToken).toHaveBeenCalledTimes(1); + expect(handleLLMNewToken).toHaveBeenCalledWith('token6'); + }); + }); +}); diff --git a/x-pack/packages/kbn-langchain/server/language_models/simple_chat_model.ts b/x-pack/packages/kbn-langchain/server/language_models/simple_chat_model.ts new file mode 100644 index 0000000000000..f13b0a53611ef --- /dev/null +++ b/x-pack/packages/kbn-langchain/server/language_models/simple_chat_model.ts @@ -0,0 +1,190 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Readable } from 'stream'; +import { + SimpleChatModel, + type BaseChatModelParams, +} from '@langchain/core/language_models/chat_models'; +import { type BaseMessage } from '@langchain/core/messages'; +import type { PluginStartContract as ActionsPluginStart } from '@kbn/actions-plugin/server'; +import { Logger } from '@kbn/logging'; +import { KibanaRequest } from '@kbn/core-http-server'; +import { v4 as uuidv4 } from 'uuid'; +import { get } from 'lodash/fp'; +import { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager'; +import { parseBedrockStream } from '../utils/bedrock'; +import { getDefaultArguments } from './constants'; + +export const getMessageContentAndRole = (prompt: string, role = 'user') => ({ + content: prompt, + role: role === 'human' ? 'user' : role, +}); + +export interface CustomChatModelInput extends BaseChatModelParams { + actions: ActionsPluginStart; + connectorId: string; + logger: Logger; + llmType?: string; + signal?: AbortSignal; + model?: string; + temperature?: number; + request: KibanaRequest; + streaming: boolean; +} + +export class ActionsClientSimpleChatModel extends SimpleChatModel { + #actions: ActionsPluginStart; + #connectorId: string; + #logger: Logger; + #request: KibanaRequest; + #traceId: string; + #signal?: AbortSignal; + llmType: string; + streaming: boolean; + model?: string; + temperature?: number; + + constructor({ + actions, + connectorId, + llmType, + logger, + model, + request, + temperature, + signal, + streaming, + }: CustomChatModelInput) { + super({}); + + this.#actions = actions; + this.#connectorId = connectorId; + this.#traceId = uuidv4(); + this.#logger = logger; + this.#signal = signal; + this.#request = request; + this.llmType = llmType ?? 'ActionsClientSimpleChatModel'; + this.model = model; + this.temperature = temperature; + // only enable streaming for bedrock + this.streaming = streaming && llmType === 'bedrock'; + } + + _llmType() { + return this.llmType; + } + + // Model type needs to be `base_chat_model` to work with LangChain OpenAI Tools + // We may want to make this configurable (ala _llmType) if different agents end up requiring different model types + // See: https://github.com/langchain-ai/langchainjs/blob/fb699647a310c620140842776f4a7432c53e02fa/langchain/src/agents/openai/index.ts#L185 + _modelType() { + return 'base_chat_model'; + } + + async _call( + messages: BaseMessage[], + options: this['ParsedCallOptions'], + runManager?: CallbackManagerForLLMRun + ): Promise { + if (!messages.length) { + throw new Error('No messages provided.'); + } + const formattedMessages = []; + if (messages.length === 2) { + messages.forEach((message, i) => { + if (typeof message.content !== 'string') { + throw new Error('Multimodal messages are not supported.'); + } + formattedMessages.push(getMessageContentAndRole(message.content, message._getType())); + }); + } else { + if (typeof messages[0].content !== 'string') { + throw new Error('Multimodal messages are not supported.'); + } + formattedMessages.push(getMessageContentAndRole(messages[0].content)); + } + this.#logger.debug( + `ActionsClientSimpleChatModel#_call\ntraceId: ${ + this.#traceId + }\nassistantMessage:\n${JSON.stringify(formattedMessages)} ` + ); + // create a new connector request body with the assistant message: + const requestBody = { + actionId: this.#connectorId, + params: { + subAction: this.streaming ? 'invokeStream' : 'invokeAI', + subActionParams: { + model: this.model, + messages: formattedMessages, + ...getDefaultArguments(this.llmType, this.temperature, options.stop), + }, + }, + }; + + // create an actions client from the authenticated request context: + const actionsClient = await this.#actions.getActionsClientWithRequest(this.#request); + + const actionResult = await actionsClient.execute(requestBody); + + if (actionResult.status === 'error') { + throw new Error( + `ActionsClientSimpleChatModel: action result status is error: ${actionResult?.message} - ${actionResult?.serviceMessage}` + ); + } + + if (!this.streaming) { + const content = get('data.message', actionResult); + + if (typeof content !== 'string') { + throw new Error( + `ActionsClientSimpleChatModel: content should be a string, but it had an unexpected type: ${typeof content}` + ); + } + + return content; // per the contact of _call, return a string + } + + // Bedrock streaming + const readable = get('data', actionResult) as Readable; + + if (typeof readable?.read !== 'function') { + throw new Error('Action result status is error: result is not streamable'); + } + + let currentOutput = ''; + let finalOutputIndex = -1; + const finalOutputStartToken = '"action":"FinalAnswer","action_input":"'; + let streamingFinished = false; + const finalOutputStopRegex = /(? { + if (finalOutputIndex === -1) { + // Remove whitespace to simplify parsing + currentOutput += token.replace(/\s/g, ''); + if (currentOutput.includes(finalOutputStartToken)) { + finalOutputIndex = currentOutput.indexOf(finalOutputStartToken); + } + } else if (!streamingFinished) { + const finalOutputEndIndex = token.search(finalOutputStopRegex); + if (finalOutputEndIndex !== -1) { + streamingFinished = true; + } else { + await runManager?.handleLLMNewToken(token); + } + } + }; + + const parsed = await parseBedrockStream( + readable, + this.#logger, + this.#signal, + handleLLMNewToken + ); + + return parsed; // per the contact of _call, return a string + } +} diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/language_models/types.ts b/x-pack/packages/kbn-langchain/server/language_models/types.ts similarity index 63% rename from x-pack/packages/kbn-elastic-assistant-common/impl/language_models/types.ts rename to x-pack/packages/kbn-langchain/server/language_models/types.ts index e4d582f02495d..df866bdf30eb7 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/language_models/types.ts +++ b/x-pack/packages/kbn-langchain/server/language_models/types.ts @@ -6,15 +6,12 @@ */ import { LangChainTracer } from '@langchain/core/tracers/tracer_langchain'; -import { - ChatCompletionContentPart, - ChatCompletionCreateParamsNonStreaming, -} from 'openai/resources/chat/completions'; +import type OpenAI from 'openai'; export interface InvokeAIActionParamsSchema { messages: Array<{ role: string; - content: string | ChatCompletionContentPart[]; + content: string | OpenAI.ChatCompletionContentPart[]; name?: string; function_call?: { arguments: string; @@ -32,11 +29,16 @@ export interface InvokeAIActionParamsSchema { }>; tool_call_id?: string; }>; - model?: ChatCompletionCreateParamsNonStreaming['model']; - n?: ChatCompletionCreateParamsNonStreaming['n']; - stop?: ChatCompletionCreateParamsNonStreaming['stop']; - temperature?: ChatCompletionCreateParamsNonStreaming['temperature']; - functions?: ChatCompletionCreateParamsNonStreaming['functions']; + model?: OpenAI.ChatCompletionCreateParamsNonStreaming['model']; + n?: OpenAI.ChatCompletionCreateParamsNonStreaming['n']; + stop?: OpenAI.ChatCompletionCreateParamsNonStreaming['stop']; + temperature?: OpenAI.ChatCompletionCreateParamsNonStreaming['temperature']; + functions?: OpenAI.ChatCompletionCreateParamsNonStreaming['functions']; + signal?: AbortSignal; + timeout?: number; +} +export interface RunActionParamsSchema { + body: string; signal?: AbortSignal; timeout?: number; } diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/utils/bedrock.test.ts b/x-pack/packages/kbn-langchain/server/utils/bedrock.test.ts similarity index 98% rename from x-pack/packages/kbn-elastic-assistant-common/impl/utils/bedrock.test.ts rename to x-pack/packages/kbn-langchain/server/utils/bedrock.test.ts index c6e3462e9534e..dde759f447445 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/utils/bedrock.test.ts +++ b/x-pack/packages/kbn-langchain/server/utils/bedrock.test.ts @@ -7,7 +7,7 @@ import { EventStreamCodec } from '@smithy/eventstream-codec'; import { fromUtf8, toUtf8 } from '@smithy/util-utf8'; -import { handleBedrockChunk } from '../..'; +import { handleBedrockChunk } from './bedrock'; const getContentBlockDelta = (completion: string) => ({ type: 'content_block_delta', diff --git a/x-pack/packages/kbn-langchain/server/utils/bedrock.ts b/x-pack/packages/kbn-langchain/server/utils/bedrock.ts new file mode 100644 index 0000000000000..4b0b6ca245ff2 --- /dev/null +++ b/x-pack/packages/kbn-langchain/server/utils/bedrock.ts @@ -0,0 +1,208 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { finished } from 'stream/promises'; +import { Readable } from 'stream'; +import { Logger } from '@kbn/core/server'; +import { EventStreamCodec } from '@smithy/eventstream-codec'; +import { fromUtf8, toUtf8 } from '@smithy/util-utf8'; + +type StreamParser = ( + responseStream: Readable, + logger: Logger, + abortSignal?: AbortSignal, + tokenHandler?: (token: string) => void +) => Promise; + +export const parseBedrockStream: StreamParser = async ( + responseStream, + logger, + abortSignal, + tokenHandler +) => { + const responseBuffer: Uint8Array[] = []; + if (abortSignal) { + abortSignal.addEventListener('abort', () => { + responseStream.destroy(new Error('Aborted')); + return parseBedrockBuffer(responseBuffer, logger); + }); + } + responseStream.on('data', (chunk) => { + // special encoding for bedrock, do not attempt to convert to string + responseBuffer.push(chunk); + if (tokenHandler) { + // Initialize an empty Uint8Array to store the concatenated buffer. + const bedrockBuffer: Uint8Array = new Uint8Array(0); + handleBedrockChunk({ chunk, bedrockBuffer, logger, chunkHandler: tokenHandler }); + } + }); + + await finished(responseStream).catch((err) => { + if (abortSignal?.aborted) { + logger.info('Bedrock stream parsing was aborted.'); + } else { + throw err; + } + }); + + return parseBedrockBuffer(responseBuffer, logger); +}; + +/** + * Parses a Bedrock buffer from an array of chunks. + * + * @param {Uint8Array[]} chunks - Array of Uint8Array chunks to be parsed. + * @returns {string} - Parsed string from the Bedrock buffer. + */ +const parseBedrockBuffer = (chunks: Uint8Array[], logger: Logger): string => { + // Initialize an empty Uint8Array to store the concatenated buffer. + let bedrockBuffer: Uint8Array = new Uint8Array(0); + + // Map through each chunk to process the Bedrock buffer. + return chunks + .map((chunk) => { + const processedChunk = handleBedrockChunk({ chunk, bedrockBuffer, logger }); + bedrockBuffer = processedChunk.bedrockBuffer; + return processedChunk.decodedChunk; + }) + .join(''); +}; + +/** + * Handle a chunk of data from the bedrock API. + * @param chunk - The chunk of data to process. + * @param bedrockBuffer - The buffer containing the current data. + * @param chunkHandler - Optional function to handle the chunk once it has been processed. + * @returns {decodedChunk, bedrockBuffer } - The decoded chunk and the updated buffer. + */ +export const handleBedrockChunk = ({ + chunk, + bedrockBuffer, + chunkHandler, + logger, +}: { + chunk: Uint8Array; + bedrockBuffer: Uint8Array; + chunkHandler?: (chunk: string) => void; + logger?: Logger; +}): { decodedChunk: string; bedrockBuffer: Uint8Array } => { + // Concatenate the current chunk to the existing buffer. + let newBuffer = concatChunks(bedrockBuffer, chunk); + // Get the length of the next message in the buffer. + let messageLength = getMessageLength(newBuffer); + // Initialize an array to store fully formed message chunks. + const buildChunks = []; + // Process the buffer until no complete messages are left. + while (newBuffer.byteLength > 0 && newBuffer.byteLength >= messageLength) { + // Extract a chunk of the specified length from the buffer. + const extractedChunk = newBuffer.slice(0, messageLength); + // Add the extracted chunk to the array of fully formed message chunks. + buildChunks.push(extractedChunk); + // Remove the processed chunk from the buffer. + newBuffer = newBuffer.slice(messageLength); + // Get the length of the next message in the updated buffer. + messageLength = getMessageLength(newBuffer); + } + + const awsDecoder = new EventStreamCodec(toUtf8, fromUtf8); + + // Decode and parse each message chunk, extracting the completion. + const decodedChunk = buildChunks + .map((bChunk) => { + const event = awsDecoder.decode(bChunk); + const body = JSON.parse( + Buffer.from(JSON.parse(new TextDecoder().decode(event.body)).bytes, 'base64').toString() + ); + const decodedContent = prepareBedrockOutput(body, logger); + if (chunkHandler) { + chunkHandler(decodedContent); + } + return decodedContent; + }) + .join(''); + return { decodedChunk, bedrockBuffer: newBuffer }; +}; + +/** + * Gets the length of the next message from the buffer. + * + * @param {Uint8Array} buffer - Buffer containing the message. + * @returns {number} - Length of the next message. + */ +function getMessageLength(buffer: Uint8Array): number { + // If the buffer is empty, return 0. + if (buffer.byteLength === 0) return 0; + // Create a DataView to read the Uint32 value at the beginning of the buffer. + const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength); + // Read and return the Uint32 value (message length). + return view.getUint32(0, false); +} + +/** + * Concatenates two Uint8Array buffers. + * + * @param {Uint8Array} a - First buffer. + * @param {Uint8Array} b - Second buffer. + * @returns {Uint8Array} - Concatenated buffer. + */ +function concatChunks(a: Uint8Array, b: Uint8Array): Uint8Array { + const newBuffer = new Uint8Array(a.length + b.length); + // Copy the contents of the first buffer to the new buffer. + newBuffer.set(a); + // Copy the contents of the second buffer to the new buffer starting from the end of the first buffer. + newBuffer.set(b, a.length); + return newBuffer; +} + +interface CompletionChunk { + type?: string; + delta?: { + type?: string; + text?: string; + stop_reason?: null | string; + stop_sequence?: null | string; + }; + message?: { content: Array<{ text?: string; type: string }> }; + content_block?: { type: string; text: string }; +} + +/** + * Prepare the streaming output from the bedrock API + * @param responseBody + * @returns string + */ +const prepareBedrockOutput = (responseBody: CompletionChunk, logger?: Logger): string => { + if (responseBody.type && responseBody.type.length) { + if (responseBody.type === 'message_start' && responseBody.message) { + return parseContent(responseBody.message.content); + } else if ( + responseBody.type === 'content_block_delta' && + responseBody.delta?.type === 'text_delta' && + typeof responseBody.delta?.text === 'string' + ) { + return responseBody.delta.text; + } + } + logger?.warn(`Failed to parse bedrock chunk ${JSON.stringify(responseBody)}`); + return ''; +}; + +/** + * Parse the content from the bedrock API + * @param content + * @returns string + */ +function parseContent(content: Array<{ text?: string; type: string }>): string { + let parsedContent = ''; + if (content.length === 1 && content[0].type === 'text' && content[0].text) { + parsedContent = content[0].text; + } else if (content.length > 1) { + // this case should not happen, but here is a fallback + parsedContent = content.reduce((acc, { text }) => (text ? `${acc}\n${text}` : acc), ''); + } + return parsedContent; +} diff --git a/packages/solution-nav/es/tsconfig.json b/x-pack/packages/kbn-langchain/tsconfig.json similarity index 63% rename from packages/solution-nav/es/tsconfig.json rename to x-pack/packages/kbn-langchain/tsconfig.json index 0b379d8cbe17f..92dc5ebd33911 100644 --- a/packages/solution-nav/es/tsconfig.json +++ b/x-pack/packages/kbn-langchain/tsconfig.json @@ -4,19 +4,20 @@ "outDir": "target/types", "types": [ "jest", - "node", - "react" + "node" ] }, "include": [ "**/*.ts", - "**/*.tsx", ], "exclude": [ "target/**/*" ], "kbn_references": [ - "@kbn/core-chrome-browser", - "@kbn/i18n", - ], + "@kbn/core", + "@kbn/logging", + "@kbn/actions-plugin", + "@kbn/logging-mocks", + "@kbn/core-http-server" + ] } diff --git a/x-pack/packages/ml/aiops_components/src/dual_brush/dual_brush.tsx b/x-pack/packages/ml/aiops_components/src/dual_brush/dual_brush.tsx index fe5eceb9041f9..43d498aa98905 100644 --- a/x-pack/packages/ml/aiops_components/src/dual_brush/dual_brush.tsx +++ b/x-pack/packages/ml/aiops_components/src/dual_brush/dual_brush.tsx @@ -233,10 +233,14 @@ export const DualBrush: FC = (props) => { ]); } - brushes.current[0].start = snappedWindowParameters.baselineMin; - brushes.current[0].end = snappedWindowParameters.baselineMax; - brushes.current[1].start = snappedWindowParameters.deviationMin; - brushes.current[1].end = snappedWindowParameters.deviationMax; + if (id === 'baseline') { + brushes.current[0].start = snappedWindowParameters.baselineMin; + brushes.current[0].end = snappedWindowParameters.baselineMax; + } + if (id === 'deviation') { + brushes.current[1].start = snappedWindowParameters.deviationMin; + brushes.current[1].end = snappedWindowParameters.deviationMax; + } if (onChange) { onChange(snappedWindowParameters, newBrushPx); @@ -263,7 +267,10 @@ export const DualBrush: FC = (props) => { return 'aiopsBrush' + b.id.charAt(0).toUpperCase() + b.id.slice(1); }) .each((brushObject: DualBrush, i, n) => { - const x = d3.scaleLinear().domain([min, max]).rangeRound([0, widthRef.current]); + const x = d3 + .scaleLinear() + .domain([minRef.current, maxRef.current]) + .rangeRound([0, widthRef.current]); // Ensure brush style is applied brushObject.brush.extent([ [0, BRUSH_MARGIN], diff --git a/x-pack/packages/ml/aiops_log_pattern_analysis/create_category_request.ts b/x-pack/packages/ml/aiops_log_pattern_analysis/create_category_request.ts index 0a15fd50e1c4b..d32970cf4c519 100644 --- a/x-pack/packages/ml/aiops_log_pattern_analysis/create_category_request.ts +++ b/x-pack/packages/ml/aiops_log_pattern_analysis/create_category_request.ts @@ -32,7 +32,8 @@ export function createCategoryRequest( wrap: ReturnType['wrap'], intervalMs?: number, additionalFilter?: CategorizationAdditionalFilter, - useStandardTokenizer: boolean = true + useStandardTokenizer: boolean = true, + includeSparkline: boolean = true ) { const query = createCategorizeQuery(queryIn, timeField, timeRange); const aggs = { @@ -50,7 +51,7 @@ export function createCategoryRequest( _source: field, }, }, - ...(intervalMs + ...(intervalMs && includeSparkline ? { sparkline: { date_histogram: { @@ -76,6 +77,16 @@ export function createCategoryRequest( _source: field, }, }, + ...(intervalMs + ? { + sparkline: { + date_histogram: { + field: timeField, + fixed_interval: `${intervalMs}ms`, + }, + }, + } + : {}), ...(additionalFilter.field ? { sub_field: { diff --git a/x-pack/packages/ml/aiops_log_pattern_analysis/embeddable.ts b/x-pack/packages/ml/aiops_log_pattern_analysis/embeddable.ts new file mode 100644 index 0000000000000..57c6b144c15d0 --- /dev/null +++ b/x-pack/packages/ml/aiops_log_pattern_analysis/embeddable.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Query, AggregateQuery, Filter } from '@kbn/es-query'; +import type { SavedSearch } from '@kbn/saved-search-plugin/public'; +import type { DataView } from '@kbn/data-views-plugin/public'; + +export interface EmbeddablePatternAnalysisInput { + dataView: DataView; + savedSearch?: SavedSearch | null; + query?: T; + filters?: Filter[]; + embeddingOrigin?: string; + switchToDocumentView?: () => void; + lastReloadRequestTime?: number; +} diff --git a/x-pack/packages/ml/aiops_log_pattern_analysis/process_category_results.ts b/x-pack/packages/ml/aiops_log_pattern_analysis/process_category_results.ts index af98fa0d71e02..6a98c0ac4a5ea 100644 --- a/x-pack/packages/ml/aiops_log_pattern_analysis/process_category_results.ts +++ b/x-pack/packages/ml/aiops_log_pattern_analysis/process_category_results.ts @@ -11,7 +11,7 @@ import type { estypes } from '@elastic/elasticsearch'; import type { createRandomSamplerWrapper } from '@kbn/ml-random-sampler-utils'; -import type { Category, CategoriesAgg, CatResponse } from './types'; +import type { Category, CategoriesAgg, CatResponse, Sparkline } from './types'; export function processCategoryResults( result: CatResponse, @@ -29,24 +29,17 @@ export function processCategoryResults( ) as CategoriesAgg; const categories: Category[] = buckets.map((b) => { - const sparkline = - b.sparkline === undefined - ? {} - : b.sparkline.buckets.reduce>((acc2, cur2) => { - acc2[cur2.key] = cur2.doc_count; - return acc2; - }, {}); - return { key: b.key, count: b.doc_count, examples: b.examples.hits.hits.map((h) => get(h._source, field)), - sparkline, + sparkline: getSparkline(b.sparkline), subTimeRangeCount: b.sub_time_range?.buckets[0].doc_count ?? undefined, subFieldCount: b.sub_time_range?.buckets[0].sub_field?.doc_count ?? undefined, subFieldExamples: b.sub_time_range?.buckets[0].examples.hits.hits.map((h) => get(h._source, field)) ?? undefined, + subFieldSparkline: getSparkline(b.sub_time_range?.buckets[0].sparkline), regex: b.regex, }; }); @@ -59,3 +52,12 @@ export function processCategoryResults( hasExamples, }; } + +function getSparkline(sparkline?: Sparkline) { + return sparkline === undefined + ? {} + : sparkline.buckets.reduce>((acc, cur) => { + acc[cur.key] = cur.doc_count; + return acc; + }, {}); +} diff --git a/x-pack/packages/ml/aiops_log_pattern_analysis/tsconfig.json b/x-pack/packages/ml/aiops_log_pattern_analysis/tsconfig.json index edf2bc92db1a3..ac3480d1d5a8b 100644 --- a/x-pack/packages/ml/aiops_log_pattern_analysis/tsconfig.json +++ b/x-pack/packages/ml/aiops_log_pattern_analysis/tsconfig.json @@ -20,5 +20,8 @@ "@kbn/config-schema", "@kbn/i18n", "@kbn/ml-runtime-field-utils", + "@kbn/es-query", + "@kbn/saved-search-plugin", + "@kbn/data-views-plugin", ] } diff --git a/x-pack/packages/ml/aiops_log_pattern_analysis/types.ts b/x-pack/packages/ml/aiops_log_pattern_analysis/types.ts index 06179262946e2..2ea11170df226 100644 --- a/x-pack/packages/ml/aiops_log_pattern_analysis/types.ts +++ b/x-pack/packages/ml/aiops_log_pattern_analysis/types.ts @@ -13,6 +13,7 @@ export interface Category { subTimeRangeCount?: number; subFieldCount?: number; subFieldExamples?: string[]; + subFieldSparkline?: Record; examples: string[]; sparkline?: Record; regex: string; @@ -22,6 +23,10 @@ interface CategoryExamples { hits: { hits: Array<{ _source: { message: string } }> }; } +export interface Sparkline { + buckets: Array<{ key_as_string: string; key: number; doc_count: number }>; +} + export interface CategoriesAgg { categories: { buckets: Array<{ @@ -29,9 +34,7 @@ export interface CategoriesAgg { doc_count: number; examples: CategoryExamples; regex: string; - sparkline: { - buckets: Array<{ key_as_string: string; key: number; doc_count: number }>; - }; + sparkline: Sparkline; sub_time_range?: { buckets: Array<{ key: number; @@ -44,6 +47,7 @@ export interface CategoriesAgg { doc_count: number; }; examples: CategoryExamples; + sparkline: Sparkline; }>; }; }>; 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 9cd7bd3a3acb8..98dbd11398174 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 @@ -56,8 +56,18 @@ export const getSignificantTermRequest = ( ]; } - const pValueAgg: Record<'change_point_p_value', estypes.AggregationsAggregationContainer> = { - change_point_p_value: { + const pValueAgg: Record< + 'sig_term_p_value' | 'distinct_count', + estypes.AggregationsAggregationContainer + > = { + // Used to identify fields with only one distinct value which we'll ignore in the analysis. + distinct_count: { + cardinality: { + field: fieldName, + }, + }, + // Used to calculate the p-value for terms of the field. + sig_term_p_value: { significant_terms: { field: fieldName, background_filter: { @@ -158,13 +168,26 @@ export const fetchSignificantTermPValues = async ( } const overallResult = ( - randomSamplerWrapper.unwrap(resp.aggregations) as Record<'change_point_p_value', Aggs> - ).change_point_p_value; + randomSamplerWrapper.unwrap(resp.aggregations) as Record<'sig_term_p_value', Aggs> + ).sig_term_p_value; + + const distinctCount = ( + randomSamplerWrapper.unwrap(resp.aggregations) as Record< + 'distinct_count', + estypes.AggregationsCardinalityAggregate + > + ).distinct_count.value; for (const bucket of overallResult.buckets) { const pValue = Math.exp(-bucket.score); - if (typeof pValue === 'number' && pValue < LOG_RATE_ANALYSIS_SETTINGS.P_VALUE_THRESHOLD) { + if ( + typeof pValue === 'number' && + // Skip items where the p-value is not significant. + pValue < LOG_RATE_ANALYSIS_SETTINGS.P_VALUE_THRESHOLD && + // Skip items where the field has only one distinct value. + distinctCount > 1 + ) { result.push({ key: `${fieldName}:${String(bucket.key)}`, type: SIGNIFICANT_ITEM_TYPE.KEYWORD, diff --git a/x-pack/packages/ml/date_picker/index.ts b/x-pack/packages/ml/date_picker/index.ts index 1a949a5d1e1d1..b68ce8d9314c0 100644 --- a/x-pack/packages/ml/date_picker/index.ts +++ b/x-pack/packages/ml/date_picker/index.ts @@ -5,6 +5,7 @@ * 2.0. */ +export { getTimeFieldRange } from './src/services/time_field_range'; export { DatePickerContextProvider, type DatePickerDependencies, diff --git a/x-pack/packages/ml/date_picker/src/services/time_field_range.ts b/x-pack/packages/ml/date_picker/src/services/time_field_range.ts index 92d71f582a1ef..f935c4577b394 100644 --- a/x-pack/packages/ml/date_picker/src/services/time_field_range.ts +++ b/x-pack/packages/ml/date_picker/src/services/time_field_range.ts @@ -40,6 +40,8 @@ interface GetTimeFieldRangeOptions { * API path ('/internal/file_upload/time_field_range') */ path: string; + + signal?: AbortSignal; } /** @@ -48,12 +50,13 @@ interface GetTimeFieldRangeOptions { * @returns GetTimeFieldRangeResponse */ export async function getTimeFieldRange(options: GetTimeFieldRangeOptions) { - const { http, path, ...body } = options; + const { http, path, signal, ...body } = options; return await http.fetch({ path, method: 'POST', body: JSON.stringify(body), version: '1', + ...(signal ? { signal } : {}), }); } diff --git a/x-pack/packages/ml/response_stream/client/constants.ts b/x-pack/packages/ml/response_stream/client/constants.ts new file mode 100644 index 0000000000000..52d2aedaf8352 --- /dev/null +++ b/x-pack/packages/ml/response_stream/client/constants.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const DATA_THROTTLE_MS = 100; diff --git a/x-pack/packages/ml/response_stream/client/index.ts b/x-pack/packages/ml/response_stream/client/index.ts index a8b02cecd9cf6..a0bc59c34deec 100644 --- a/x-pack/packages/ml/response_stream/client/index.ts +++ b/x-pack/packages/ml/response_stream/client/index.ts @@ -6,4 +6,5 @@ */ export { fetchStream } from './fetch_stream'; +export { cancelStream, startStream, streamSlice } from './stream_slice'; export { useFetchStream } from './use_fetch_stream'; diff --git a/x-pack/packages/ml/response_stream/client/stream_slice.ts b/x-pack/packages/ml/response_stream/client/stream_slice.ts new file mode 100644 index 0000000000000..d8b7888dd4c6f --- /dev/null +++ b/x-pack/packages/ml/response_stream/client/stream_slice.ts @@ -0,0 +1,148 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { AnyAction, PayloadAction } from '@reduxjs/toolkit'; +import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'; +import { batch } from 'react-redux'; + +import type { HttpSetup, HttpFetchOptions } from '@kbn/core/public'; +import { fetchStream } from './fetch_stream'; +import { DATA_THROTTLE_MS } from './constants'; + +/** + * Async thunk to start the stream. + */ +export const startStream = createAsyncThunk( + 'stream/start', + async ( + options: { + http: HttpSetup; + endpoint: string; + apiVersion?: string; + abortCtrl: React.MutableRefObject; + body?: any; + headers?: HttpFetchOptions['headers']; + }, + thunkApi + ) => { + const { http, endpoint, apiVersion, abortCtrl, body, headers } = options; + + const fetchState = { isActive: true }; + + // Custom buffering to avoid hammering the DOM with updates. + // We can revisit this once Kibana is on React 18. + const actionBuffer: AnyAction[] = []; + function flushBuffer(withTimeout = true) { + batch(() => { + for (const action of actionBuffer) { + thunkApi.dispatch(action); + } + }); + actionBuffer.length = 0; + + if (withTimeout) { + setTimeout(() => { + if (fetchState.isActive) { + flushBuffer(); + } + }, DATA_THROTTLE_MS); + } + } + + flushBuffer(); + + for await (const [fetchStreamError, action] of fetchStream( + http, + endpoint, + apiVersion, + abortCtrl, + body, + true, + headers + )) { + if (fetchStreamError !== null) { + actionBuffer.push(addError(fetchStreamError)); + } else if (action) { + actionBuffer.push(action); + } + } + + fetchState.isActive = false; + flushBuffer(false); + }, + { + condition: (_, { getState }) => { + // This is a bit of a hack to prevent instant restarts while the stream is running. + // The problem is that in RTK v1, async thunks cannot be made part of the slice, + // so they will not know the namespace used where they run in. We just assume + // `stream` here as the namespace, if it's a custom one, this will not work. + // RTK v2 will allow async thunks to be part of the slice, a draft PR to upgrade + // is up there: https://github.com/elastic/kibana/pull/178986 + try { + const s = getState() as { stream?: StreamState }; + + if (s.stream === undefined) { + return true; + } + + // If the stream was running, the extra reducers will also have set + // and error, so we need to prevent the stream from starting again. + if (s.stream.isRunning && s.stream.errors.length > 0) { + return false; + } + } catch (e) { + return true; + } + }, + } +); + +export interface StreamState { + errors: string[]; + isCancelled: boolean; + isRunning: boolean; +} + +function getDefaultState(): StreamState { + return { + errors: [], + isCancelled: false, + isRunning: false, + }; +} + +export const streamSlice = createSlice({ + name: 'stream', + initialState: getDefaultState(), + reducers: { + addError: (state: StreamState, action: PayloadAction) => { + state.errors.push(action.payload); + }, + cancelStream: (state: StreamState) => { + state.isCancelled = true; + state.isRunning = false; + }, + }, + extraReducers: (builder) => { + builder.addCase(startStream.pending, (state) => { + if (state.isRunning) { + state.errors.push('Instant restart while running not supported yet.'); + return; + } + + state.errors = []; + state.isCancelled = false; + state.isRunning = true; + }); + builder.addCase(startStream.fulfilled, (state) => { + state.isRunning = false; + }); + }, +}); + +// Action creators are generated for each case reducer function +export const { addError, cancelStream } = streamSlice.actions; diff --git a/x-pack/packages/ml/response_stream/client/use_fetch_stream.ts b/x-pack/packages/ml/response_stream/client/use_fetch_stream.ts index 55950c6ee8f77..1e0deeb7f8e26 100644 --- a/x-pack/packages/ml/response_stream/client/use_fetch_stream.ts +++ b/x-pack/packages/ml/response_stream/client/use_fetch_stream.ts @@ -19,8 +19,7 @@ import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { fetchStream } from './fetch_stream'; import { stringReducer, type StringReducer } from './string_reducer'; - -const DATA_THROTTLE_MS = 100; +import { DATA_THROTTLE_MS } from './constants'; // This pattern with a dual ternary allows us to default to StringReducer // and if a custom reducer is supplied fall back to that one instead. @@ -80,7 +79,8 @@ export function useFetchStream>( // a lot of unnecessary re-renders even in combination with `useThrottle`. // We're now using `dataRef` to allow updates outside of the render cycle. // When the stream is running, we'll update `data` with the `dataRef` value - // periodically. + // periodically. This will get simpler with React 18 where we + // can make use of `useDeferredValue`. const [data, setData] = useState(reducerWithFallback.initialState); const dataRef = useRef(reducerWithFallback.initialState); diff --git a/x-pack/packages/security-solution/features/src/product_features_keys.ts b/x-pack/packages/security-solution/features/src/product_features_keys.ts index 315dcb2730738..5f6cd5f93b54b 100644 --- a/x-pack/packages/security-solution/features/src/product_features_keys.ts +++ b/x-pack/packages/security-solution/features/src/product_features_keys.ts @@ -111,6 +111,7 @@ export enum SecuritySubFeatureId { processOperations = 'processOperationsSubFeature', fileOperations = 'fileOperationsSubFeature', executeAction = 'executeActionSubFeature', + scanAction = 'scanActionSubFeature', } /** Sub-features IDs for Cases */ diff --git a/x-pack/packages/security-solution/features/src/security/index.ts b/x-pack/packages/security-solution/features/src/security/index.ts index 0815fcd915cb2..e59b0662dd975 100644 --- a/x-pack/packages/security-solution/features/src/security/index.ts +++ b/x-pack/packages/security-solution/features/src/security/index.ts @@ -7,7 +7,10 @@ import type { SecuritySubFeatureId } from '../product_features_keys'; import type { ProductFeatureParams } from '../types'; import { getSecurityBaseKibanaFeature } from './kibana_features'; -import { securitySubFeaturesMap, getSecurityBaseKibanaSubFeatureIds } from './kibana_sub_features'; +import { + getSecuritySubFeaturesMap, + getSecurityBaseKibanaSubFeatureIds, +} from './kibana_sub_features'; import type { SecurityFeatureParams } from './types'; export const getSecurityFeature = ( @@ -15,5 +18,5 @@ export const getSecurityFeature = ( ): ProductFeatureParams => ({ baseKibanaFeature: getSecurityBaseKibanaFeature(params), baseKibanaSubFeatureIds: getSecurityBaseKibanaSubFeatureIds(params), - subFeaturesMap: securitySubFeaturesMap, + subFeaturesMap: getSecuritySubFeaturesMap(params), }); diff --git a/x-pack/packages/security-solution/features/src/security/kibana_sub_features.ts b/x-pack/packages/security-solution/features/src/security/kibana_sub_features.ts index ae7d1dd3eb803..24c8d0a57e772 100644 --- a/x-pack/packages/security-solution/features/src/security/kibana_sub_features.ts +++ b/x-pack/packages/security-solution/features/src/security/kibana_sub_features.ts @@ -554,6 +554,47 @@ const executeActionSubFeature: SubFeatureConfig = { ], }; +// 8.15 feature +const scanActionSubFeature: SubFeatureConfig = { + requireAllSpaces: true, + privilegesTooltip: i18n.translate( + 'securitySolutionPackages.features.featureRegistry.subFeatures.scanOperations.privilegesTooltip', + { + defaultMessage: 'All Spaces is required for Scan Operations access.', + } + ), + name: i18n.translate( + 'securitySolutionPackages.features.featureRegistry.subFeatures.scanOperations', + { + defaultMessage: 'Scan Operations', + } + ), + description: i18n.translate( + 'securitySolutionPackages.features.featureRegistry.subFeatures.scanOperations.description', + { + defaultMessage: 'Perform folder scan response actions in the response console.', + } + ), + privilegeGroups: [ + { + groupType: 'mutually_exclusive', + privileges: [ + { + api: [`${APP_ID}-writeScanOperations`], + id: 'scan_operations_all', + includeIn: 'none', + name: 'All', + savedObject: { + all: [], + read: [], + }, + ui: ['writeScanOperations'], + }, + ], + }, + ], +}; + const endpointExceptionsSubFeature: SubFeatureConfig = { requireAllSpaces: true, privilegesTooltip: i18n.translate( @@ -615,8 +656,11 @@ export const getSecurityBaseKibanaSubFeatureIds = ( * Defines all the Security Assistant subFeatures available. * The order of the subFeatures is the order they will be displayed */ -export const securitySubFeaturesMap = Object.freeze( - new Map([ + +export const getSecuritySubFeaturesMap = ({ + experimentalFeatures, +}: SecurityFeatureParams): Map => { + const securitySubFeaturesList: Array<[SecuritySubFeatureId, SubFeatureConfig]> = [ [SecuritySubFeatureId.endpointList, endpointListSubFeature], [SecuritySubFeatureId.endpointExceptions, endpointExceptionsSubFeature], [SecuritySubFeatureId.trustedApplications, trustedApplicationsSubFeature], @@ -629,5 +673,15 @@ export const securitySubFeaturesMap = Object.freeze( [SecuritySubFeatureId.processOperations, processOperationsSubFeature], [SecuritySubFeatureId.fileOperations, fileOperationsSubFeature], [SecuritySubFeatureId.executeAction, executeActionSubFeature], - ]) -); + ]; + + if (experimentalFeatures.responseActionScanEnabled) { + securitySubFeaturesList.push([SecuritySubFeatureId.scanAction, scanActionSubFeature]); + } + + const securitySubFeaturesMap = new Map( + securitySubFeaturesList + ); + + return Object.freeze(securitySubFeaturesMap); +}; diff --git a/x-pack/packages/security-solution/features/src/security/product_feature_config.ts b/x-pack/packages/security-solution/features/src/security/product_feature_config.ts index d9f52ebf54192..7fc2413e85e89 100644 --- a/x-pack/packages/security-solution/features/src/security/product_feature_config.ts +++ b/x-pack/packages/security-solution/features/src/security/product_feature_config.ts @@ -105,6 +105,7 @@ export const securityDefaultProductFeaturesConfig: DefaultSecurityProductFeature SecuritySubFeatureId.processOperations, SecuritySubFeatureId.fileOperations, SecuritySubFeatureId.executeAction, + SecuritySubFeatureId.scanAction, ], subFeaturesPrivileges: [ { diff --git a/x-pack/packages/security-solution/upselling/helpers/index.tsx b/x-pack/packages/security-solution/upselling/helpers/index.tsx new file mode 100644 index 0000000000000..efa0d6ca5a46e --- /dev/null +++ b/x-pack/packages/security-solution/upselling/helpers/index.tsx @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { Suspense } from 'react'; +import { EuiLoadingSpinner } from '@elastic/eui'; + +export const withSuspenseUpsell = ( + Component: React.ComponentType +): React.FC => + function WithSuspenseUpsell(props) { + return ( + }> + + + ); + }; diff --git a/x-pack/packages/security-solution/upselling/pages/entity_analytics.test.tsx b/x-pack/packages/security-solution/upselling/pages/entity_analytics.test.tsx index 244441d69eed8..728a4ccc0e6b9 100644 --- a/x-pack/packages/security-solution/upselling/pages/entity_analytics.test.tsx +++ b/x-pack/packages/security-solution/upselling/pages/entity_analytics.test.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; import { render } from '@testing-library/react'; -import EntityAnalyticsUpsellingComponent from './entity_analytics'; +import { EntityAnalyticsUpsellingPage } from './entity_analytics'; jest.mock('@kbn/security-solution-navigation', () => { const original = jest.requireActual('@kbn/security-solution-navigation'); @@ -21,54 +21,33 @@ jest.mock('@kbn/security-solution-navigation', () => { describe('EntityAnalyticsUpselling', () => { it('should render', () => { const { getByTestId } = render( - - ); - expect(getByTestId('paywallCardDescription')).toBeInTheDocument(); - }); - - it('should throw exception when requiredLicense and requiredProduct are not provided', () => { - expect(() => render()).toThrow(); - }); - - it('should show product message when requiredProduct is provided', () => { - const { getByTestId } = render( - ); - - expect(getByTestId('paywallCardDescription')).toHaveTextContent( - 'Entity risk scoring capability is available in our TEST PRODUCT license tier' - ); + expect(getByTestId('paywallCardDescription')).toBeInTheDocument(); }); - it('should show product badge when requiredProduct is provided', () => { + it('should show upgrade label badge', () => { const { getByText } = render( - ); expect(getByText('TEST PRODUCT')).toBeInTheDocument(); }); - it('should show license message when requiredLicense is provided', () => { + it('should show license message', () => { const { getByTestId } = render( - - ); - - expect(getByTestId('paywallCardDescription')).toHaveTextContent( - 'This feature is available with TEST LICENSE or higher subscription' - ); - }); - - it('should show license badge when requiredLicense is provided', () => { - const { getByText } = render( - + ); - expect(getByText('TEST LICENSE')).toBeInTheDocument(); + expect(getByTestId('paywallCardDescription')).toHaveTextContent('test upgrade message'); }); }); diff --git a/x-pack/packages/security-solution/upselling/pages/entity_analytics.tsx b/x-pack/packages/security-solution/upselling/pages/entity_analytics.tsx index 56507dd0f2b46..692e49dfbfd41 100644 --- a/x-pack/packages/security-solution/upselling/pages/entity_analytics.tsx +++ b/x-pack/packages/security-solution/upselling/pages/entity_analytics.tsx @@ -5,25 +5,15 @@ * 2.0. */ -import React, { useCallback } from 'react'; -import { - EuiCard, - EuiIcon, - EuiFlexGroup, - EuiFlexItem, - EuiText, - EuiButton, - EuiTextColor, - EuiImage, - EuiPageHeader, - EuiSpacer, -} from '@elastic/eui'; +import React from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiImage, EuiPageHeader, EuiSpacer } from '@elastic/eui'; import styled from '@emotion/styled'; -import { useNavigation } from '@kbn/security-solution-navigation'; + import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; import * as i18n from './translations'; import paywallPng from '../images/entity_paywall.png'; +import { EntityAnalyticsUpsellingSection } from '../sections/entity_analytics'; const PaywallDiv = styled.div` max-width: 75%; @@ -37,81 +27,27 @@ const PaywallDiv = styled.div` padding: 0 15%; } `; -const StyledEuiCard = styled(EuiCard)` - span.euiTitle { - max-width: 540px; - display: block; - margin: 0 auto; - } -`; const EntityAnalyticsUpsellingComponent = ({ - requiredLicense, - requiredProduct, - subscriptionUrl, + upgradeMessage, + upgradeHref, + upgradeToLabel, }: { - requiredLicense?: string; - requiredProduct?: string; - subscriptionUrl?: string; + upgradeMessage: string; + upgradeToLabel: string; + upgradeHref?: string; }) => { - const { navigateTo } = useNavigation(); - - const goToSubscription = useCallback(() => { - navigateTo({ url: subscriptionUrl }); - }, [navigateTo, subscriptionUrl]); - - if (!requiredProduct && !requiredLicense) { - throw new Error('requiredProduct or requiredLicense must be defined'); - } - - const upgradeMessage = requiredProduct - ? i18n.UPGRADE_PRODUCT_MESSAGE(requiredProduct) - : i18n.UPGRADE_LICENSE_MESSAGE(requiredLicense ?? ''); - - const requiredProductOrLicense = requiredProduct ?? requiredLicense ?? ''; - return ( - } - display="subdued" - title={ -

- {i18n.ENTITY_ANALYTICS_LICENSE_DESC} -

- } - description={false} - paddingSize="xl" - > - - - -

- {upgradeMessage} -

-
- - {subscriptionUrl && ( -
- - {i18n.UPGRADE_BUTTON(requiredProductOrLicense)} - -
- )} -
-
-
-
+ @@ -125,5 +61,4 @@ const EntityAnalyticsUpsellingComponent = ({ EntityAnalyticsUpsellingComponent.displayName = 'EntityAnalyticsUpsellingComponent'; -// eslint-disable-next-line import/no-default-export -export default React.memo(EntityAnalyticsUpsellingComponent); +export const EntityAnalyticsUpsellingPage = React.memo(EntityAnalyticsUpsellingComponent); diff --git a/x-pack/packages/security-solution/upselling/pages/translations.ts b/x-pack/packages/security-solution/upselling/pages/translations.ts index f4dd5b5c081c8..c68df712769ea 100644 --- a/x-pack/packages/security-solution/upselling/pages/translations.ts +++ b/x-pack/packages/security-solution/upselling/pages/translations.ts @@ -7,23 +7,6 @@ import { i18n } from '@kbn/i18n'; -export const UPGRADE_LICENSE_MESSAGE = (requiredLicense: string) => - i18n.translate('securitySolutionPackages.entityAnalytics.paywall.upgradeLicenseMessage', { - defaultMessage: 'This feature is available with {requiredLicense} or higher subscription', - values: { - requiredLicense, - }, - }); - -export const UPGRADE_PRODUCT_MESSAGE = (requiredProduct: string) => - i18n.translate('securitySolutionPackages.entityAnalytics.paywall.upgradeProductMessage', { - defaultMessage: - 'Entity risk scoring capability is available in our {requiredProduct} license tier', - values: { - requiredProduct, - }, - }); - export const UPGRADE_BUTTON = (requiredLicenseOrProduct: string) => i18n.translate('securitySolutionPackages.entityAnalytics.paywall.upgradeButton', { defaultMessage: 'Upgrade to {requiredLicenseOrProduct}', diff --git a/x-pack/packages/security-solution/upselling/sections/entity_analytics.tsx b/x-pack/packages/security-solution/upselling/sections/entity_analytics.tsx new file mode 100644 index 0000000000000..add60f07c4ef1 --- /dev/null +++ b/x-pack/packages/security-solution/upselling/sections/entity_analytics.tsx @@ -0,0 +1,88 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { memo, useCallback } from 'react'; +import { + EuiCard, + EuiIcon, + EuiFlexGroup, + EuiFlexItem, + EuiText, + EuiTextColor, + EuiButton, +} from '@elastic/eui'; +import styled from '@emotion/styled'; + +import { useNavigation } from '@kbn/security-solution-navigation'; +import * as i18n from '../pages/translations'; + +const StyledEuiCard = styled(EuiCard)` + span.euiTitle { + max-width: 540px; + display: block; + margin: 0 auto; + } +`; + +export const EntityAnalyticsUpsellingSection = memo( + ({ + upgradeMessage, + upgradeHref, + upgradeToLabel, + }: { + upgradeMessage: string; + upgradeToLabel: string; + upgradeHref?: string; + }) => { + const { navigateTo } = useNavigation(); + const goToSubscription = useCallback(() => { + navigateTo({ url: upgradeHref }); + }, [navigateTo, upgradeHref]); + + return ( + } + display="subdued" + title={ +

+ {i18n.ENTITY_ANALYTICS_LICENSE_DESC} +

+ } + description={false} + paddingSize="xl" + > + + + +

+ {upgradeMessage} +

+
+ + {upgradeHref && ( +
+ {/* eslint-disable-next-line @elastic/eui/href-or-on-click*/} + + {i18n.UPGRADE_BUTTON(upgradeToLabel)} + +
+ )} +
+
+
+
+ ); + } +); + +EntityAnalyticsUpsellingSection.displayName = 'EntityAnalyticsUpsellingSection'; diff --git a/x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts b/x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts index 1cbf13a4ad45f..184f21ce2ddac 100644 --- a/x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts +++ b/x-pack/packages/security/plugin_types_server/src/authentication/api_keys/api_keys.ts @@ -185,6 +185,9 @@ export const crossClusterApiKeySchema = restApiKeySchema.extends({ schema.arrayOf( schema.object({ names: schema.arrayOf(schema.string()), + query: schema.maybe(schema.any()), + field_security: schema.maybe(schema.any()), + allow_restricted_indices: schema.maybe(schema.boolean()), }) ) ), diff --git a/x-pack/plugins/actions/server/usage/actions_telemetry.test.ts b/x-pack/plugins/actions/server/usage/actions_telemetry.test.ts index c3cb9d48ee9e4..b4f6d785584a4 100644 --- a/x-pack/plugins/actions/server/usage/actions_telemetry.test.ts +++ b/x-pack/plugins/actions/server/usage/actions_telemetry.test.ts @@ -24,9 +24,12 @@ describe('actions telemetry', () => { { aggregations: { byActionTypeId: { - value: { - types: { '.index': 1, '.server-log': 1, 'some.type': 1, 'another.type.': 1 }, - }, + buckets: [ + { key: '.index', doc_count: 1 }, + { key: '.server-log', doc_count: 1 }, + { key: 'some.type', doc_count: 1 }, + { key: 'another.type.', doc_count: 1 }, + ], }, }, hits: { @@ -152,10 +155,18 @@ describe('actions telemetry', () => { aggregations: { refs: { actionRefIds: { - value: { - connectorIds: { '1': 'action-0', '123': 'action-0' }, - total: 2, - }, + buckets: [ + { + key: ['1', 'action-0'], + key_as_string: '1|action-0', + doc_count: 1, + }, + { + key: ['123', 'action-0'], + key_as_string: '123|action-0', + doc_count: 1, + }, + ], }, }, hits: { @@ -217,27 +228,34 @@ describe('actions telemetry', () => { aggregations: { refs: { actionRefIds: { - value: { - connectorIds: { - '1': 'action_0', - '123': 'action_1', - 'preconfigured-alert-history-es-index': 'action_2', + buckets: [ + { + key: ['1', 'action_0'], + key_as_string: '1|action_0', + doc_count: 1, }, - total: 3, - }, + { + key: ['123', 'action_1'], + key_as_string: '123|action_1', + doc_count: 1, + }, + { + key: ['preconfigured-alert-history-es-index', 'action_2'], + key_as_string: 'preconfigured-alert-history-es-index|action_2', + doc_count: 1, + }, + ], }, }, - preconfigured_actions: { - preconfiguredActionRefIds: { - value: { - total: 1, - actionRefs: { - 'preconfigured:preconfigured-alert-history-es-index': { - actionRef: 'preconfigured:preconfigured-alert-history-es-index', - actionTypeId: '.index', - }, + actions: { + actionRefIds: { + buckets: [ + { + key: ['preconfigured:preconfigured-alert-history-es-index', '.index'], + key_as_string: 'preconfigured:preconfigured-alert-history-es-index|.index', + doc_count: 1, }, - }, + ], }, }, }, @@ -344,9 +362,12 @@ describe('actions telemetry', () => { { aggregations: { byActionTypeId: { - value: { - types: { '.index': 1, '.server-log': 1, 'some.type': 1, 'another.type.': 1 }, - }, + buckets: [ + { key: '.index', doc_count: 1 }, + { key: '.server-log', doc_count: 1 }, + { key: 'some.type', doc_count: 1 }, + { key: 'another.type.', doc_count: 1 }, + ], }, }, hits: { @@ -472,9 +493,7 @@ describe('actions telemetry', () => { { aggregations: { byActionTypeId: { - value: { - types: {}, - }, + buckets: [], }, }, hits: { @@ -517,35 +536,44 @@ describe('actions telemetry', () => { aggregations: { refs: { actionRefIds: { - value: { - connectorIds: { - '1': 'action-0', - '123': 'action-1', - '456': 'action-2', + buckets: [ + { + key: ['1', 'action-0'], + key_as_string: '1|action-0', + doc_count: 1, }, - total: 3, - }, + { + key: ['123', 'action-1'], + key_as_string: '123|action-1', + doc_count: 1, + }, + { + key: ['456', 'action-2'], + key_as_string: '456|action-2', + doc_count: 1, + }, + ], }, }, - preconfigured_actions: { - preconfiguredActionRefIds: { - value: { - total: 3, - actionRefs: { - 'preconfigured:preconfigured-alert-history-es-index': { - actionRef: 'preconfigured:preconfigured-alert-history-es-index', - actionTypeId: '.index', - }, - 'preconfigured:cloud_email': { - actionRef: 'preconfigured:cloud_email', - actionTypeId: '.email', - }, - 'preconfigured:cloud_email2': { - actionRef: 'preconfigured:cloud_email2', - actionTypeId: '.email', - }, + actions: { + actionRefIds: { + buckets: [ + { + key: ['preconfigured:preconfigured-alert-history-es-index', '.index'], + key_as_string: 'preconfigured:preconfigured-alert-history-es-index|.index', + doc_count: 1, }, - }, + { + key: ['preconfigured:cloud_email', '.email'], + key_as_string: 'preconfigured:cloud_email|.email', + doc_count: 1, + }, + { + key: ['preconfigured:cloud_email2', '.email'], + key_as_string: 'preconfigured:cloud_email2|.email', + doc_count: 1, + }, + ], }, }, }, @@ -628,30 +656,39 @@ describe('actions telemetry', () => { aggregations: { refs: { actionRefIds: { - value: { - connectorIds: { - '1': 'action-0', - '2': 'action-1', + buckets: [ + { + key: ['1', 'action-0'], + key_as_string: '1|action-0', + doc_count: 1, }, - total: 3, - }, + { + key: ['2', 'action-1'], + key_as_string: '2|action-1', + doc_count: 2, + }, + ], }, }, - system_actions: { - systemActionRefIds: { - value: { - total: 2, - actionRefs: { - 'system_action:system-connector-test.system-action': { - actionRef: 'system_action:system-connector-test.system-action', - actionTypeId: 'test.system-action', - }, - 'system_action:system-connector-test.system-action-2': { - actionRef: 'system_action:system-connector-test.system-action-2', - actionTypeId: 'test.system-action-2', - }, + actions: { + actionRefIds: { + buckets: [ + { + key: ['system_action:system-connector-test.system-action', 'test.system-action'], + key_as_string: + 'system_action:system-connector-test.system-action|test.system-action', + doc_count: 1, }, - }, + { + key: [ + 'system_action:system-connector-test.system-action-2', + 'test.system-action-2', + ], + key_as_string: + 'system_action:system-connector-test.system-action-2|test.system-action-2', + doc_count: 1, + }, + ], }, }, }, @@ -697,7 +734,7 @@ describe('actions telemetry', () => { }, "countEmailByService": Object {}, "countNamespaces": 1, - "countTotal": 5, + "countTotal": 4, "hasErrors": false, } `); @@ -711,35 +748,44 @@ describe('actions telemetry', () => { aggregations: { refs: { actionRefIds: { - value: { - connectorIds: { - '1': 'action-0', - '123': 'action-1', - '456': 'action-2', + buckets: [ + { + key: ['1', 'action-0'], + key_as_string: '1|action-0', + doc_count: 1, }, - total: 3, - }, + { + key: ['123', 'action-1'], + key_as_string: '123|action-1', + doc_count: 1, + }, + { + key: ['456', 'action-2'], + key_as_string: '456|action-2', + doc_count: 1, + }, + ], }, }, - preconfigured_actions: { - preconfiguredActionRefIds: { - value: { - total: 3, - actionRefs: { - 'preconfigured:preconfigured-alert-history-es-index': { - actionRef: 'preconfigured:preconfigured-alert-history-es-index', - actionTypeId: '.index', - }, - 'preconfigured:cloud_email': { - actionRef: 'preconfigured:cloud_email', - actionTypeId: '.email', - }, - 'preconfigured:cloud_email2': { - actionRef: 'preconfigured:cloud_email2', - actionTypeId: '.email', - }, + actions: { + actionRefIds: { + buckets: [ + { + key: ['preconfigured:preconfigured-alert-history-es-index', '.index'], + key_as_string: 'preconfigured:preconfigured-alert-history-es-index|.index', + doc_count: 1, }, - }, + { + key: ['preconfigured:cloud_email', '.email'], + key_as_string: 'preconfigured:cloud_email|.email', + doc_count: 1, + }, + { + key: ['preconfigured:cloud_email2', '.email'], + key_as_string: 'preconfigured:cloud_email2|.email', + doc_count: 1, + }, + ], }, }, }, @@ -810,24 +856,31 @@ describe('actions telemetry', () => { { aggregations: { totalExecutions: { - byConnectorTypeId: { - value: { - connectorTypes: { - '.slack': 100, - '.server-log': 20, - }, - total: 120, + refs: { + byConnectorTypeId: { + buckets: [ + { + key: '.server-log', + doc_count: 20, + }, + { + key: '.slack', + doc_count: 100, + }, + ], }, }, }, failedExecutions: { - refs: { - byConnectorTypeId: { - value: { - connectorTypes: { - '.slack': 7, - }, - total: 7, + actionSavedObjects: { + refs: { + byConnectorTypeId: { + buckets: [ + { + key: '.slack', + doc_count: 7, + }, + ], }, }, }, diff --git a/x-pack/plugins/actions/server/usage/actions_telemetry.ts b/x-pack/plugins/actions/server/usage/actions_telemetry.ts index 1f4206cace425..b7e93f5157140 100644 --- a/x-pack/plugins/actions/server/usage/actions_telemetry.ts +++ b/x-pack/plugins/actions/server/usage/actions_telemetry.ts @@ -14,65 +14,57 @@ import { } from './lib/parse_connector_type_bucket'; import { AlertHistoryEsIndexConnectorId } from '../../common'; import { ActionResult, InMemoryConnector } from '../types'; +import { + getInMemoryActions, + getActions, + getActionExecutions, + getActionsCount, +} from './lib/actions_telemetry_util'; -interface InMemoryAggRes { +export interface InMemoryAggRes { total: number; actionRefs: Record; } +export interface ByActionTypeIdAgg { + key: string; + doc_count: number; +} + +export interface ActionRefIdsAgg { + key: string[]; + key_as_string: string; + doc_count: number; +} + +export interface ConnectorAggRes { + total: number; + connectorTypes: Record; +} + export async function getTotalCount( esClient: ElasticsearchClient, kibanaIndex: string, logger: Logger, inMemoryConnectors?: InMemoryConnector[] ) { - const scriptedMetric = { - scripted_metric: { - init_script: 'state.types = [:]', - map_script: ` - String actionType = doc['action.actionTypeId'].value; - if (actionType =~ /\.gen-ai/) { - String genAiActionType = actionType +"__"+ doc['apiProvider'].value; - state.types.put(genAiActionType, state.types.containsKey(genAiActionType) ? state.types.get(genAiActionType) + 1 : 1); - } else { - state.types.put(actionType, state.types.containsKey(actionType) ? state.types.get(actionType) + 1 : 1); - } - `, - // Combine script is executed per cluster, but we already have a key-value pair per cluster. - // Despite docs that say this is optional, this script can't be blank. - combine_script: 'return state', - // Reduce script is executed across all clusters, so we need to add up all the total from each cluster - // This also needs to account for having no data - reduce_script: ` - HashMap result = new HashMap(); - HashMap combinedTypes = new HashMap(); - for (state in states) { - for (String type : state.types.keySet()) { - int typeCount = combinedTypes.containsKey(type) ? combinedTypes.get(type) + state.types.get(type) : state.types.get(type); - combinedTypes.put(type, typeCount); - } - } - - result.types = combinedTypes; - return result; - `, - }, - }; try { const searchResult = await esClient.search< unknown, - { byActionTypeId: { value: { types: Record } } } + { byActionTypeId: { buckets: ByActionTypeIdAgg[] } } >({ index: kibanaIndex, size: 0, runtime_mappings: { - apiProvider: { + calcActionTypeId: { type: 'keyword', script: { - // add apiProvider to the doc so we can use it in the scripted_metric source: ` - if (doc['action.actionTypeId'].value =~ /\.gen-ai/) { - emit(params._source["action"]["config"]["apiProvider"]) + String actionType = doc['action.actionTypeId'].value; + if (actionType =~ /\.gen-ai/) { + emit( actionType +"__"+ params._source["action"]["config"]["apiProvider"]) + } else { + emit(actionType) } `, }, @@ -85,12 +77,16 @@ export async function getTotalCount( }, }, aggs: { - byActionTypeId: scriptedMetric, + byActionTypeId: { + terms: { + field: 'calcActionTypeId', + }, + }, }, }, }); - const aggs = searchResult.aggregations?.byActionTypeId.value?.types ?? {}; + const aggs = getActionsCount(searchResult.aggregations?.byActionTypeId.buckets); const { countGenAiProviderTypes, countByType } = getCounts(aggs); if (inMemoryConnectors && inMemoryConnectors.length) { @@ -141,82 +137,6 @@ export async function getInUseTotalCount( countEmailByService: Record; countNamespaces: number; }> { - const getInMemoryActionScriptedMetric = (actionRefPrefix: string) => ({ - scripted_metric: { - init_script: 'state.actionRefs = new HashMap(); state.total = 0;', - map_script: ` - String actionRef = doc['alert.actions.actionRef'].value; - String actionTypeId = doc['alert.actions.actionTypeId'].value; - if (actionRef.startsWith('${actionRefPrefix}') && state.actionRefs[actionRef] === null) { - HashMap map = new HashMap(); - map.actionRef = actionRef; - map.actionTypeId = actionTypeId; - state.actionRefs[actionRef] = map; - state.total++; - } - `, - // Combine script is executed per cluster, but we already have a key-value pair per cluster. - // Despite docs that say this is optional, this script can't be blank. - combine_script: 'return state', - // Reduce script is executed across all clusters, so we need to add up all the total from each cluster - // This also needs to account for having no data - reduce_script: ` - Map actionRefs = [:]; - long total = 0; - for (state in states) { - if (state !== null) { - total += state.total; - for (String k : state.actionRefs.keySet()) { - actionRefs.put(k, state.actionRefs.get(k)); - } - } - } - Map result = new HashMap(); - result.total = total; - result.actionRefs = actionRefs; - return result; - `, - }, - }); - - const scriptedMetric = { - scripted_metric: { - init_script: 'state.connectorIds = new HashMap(); state.total = 0;', - map_script: ` - String connectorId = doc['references.id'].value; - String actionRef = doc['references.name'].value; - if (state.connectorIds[connectorId] === null) { - state.connectorIds[connectorId] = actionRef; - state.total++; - } - `, - // Combine script is executed per cluster, but we already have a key-value pair per cluster. - // Despite docs that say this is optional, this script can't be blank. - combine_script: 'return state', - // Reduce script is executed across all clusters, so we need to add up all the total from each cluster - // This also needs to account for having no data - reduce_script: ` - Map connectorIds = [:]; - long total = 0; - for (state in states) { - if (state !== null) { - total += state.total; - for (String k : state.connectorIds.keySet()) { - connectorIds.put(k, connectorIds.containsKey(k) ? connectorIds.get(k) + state.connectorIds.get(k) : state.connectorIds.get(k)); - } - } - } - Map result = new HashMap(); - result.total = total; - result.connectorIds = connectorIds; - return result; - `, - }, - }; - - const preconfiguredActionsScriptedMetric = getInMemoryActionScriptedMetric('preconfigured:'); - const systemActionsScriptedMetric = getInMemoryActionScriptedMetric('system_action:'); - const mustQuery = [ { bool: { @@ -300,9 +220,8 @@ export async function getInUseTotalCount( const actionResults = await esClient.search< unknown, { - refs: { actionRefIds: { value: { total: number; connectorIds: Record } } }; - preconfigured_actions: { preconfiguredActionRefIds: { value: InMemoryAggRes } }; - system_actions: { systemActionRefIds: { value: InMemoryAggRes } }; + refs: { actionRefIds: { buckets: ActionRefIdsAgg[] } }; + actions: { actionRefIds: { buckets: ActionRefIdsAgg[] } }; } >({ index: kibanaIndex, @@ -328,35 +247,48 @@ export async function getInUseTotalCount( path: 'references', }, aggs: { - actionRefIds: scriptedMetric, - }, - }, - preconfigured_actions: { - nested: { - path: 'alert.actions', - }, - aggs: { - preconfiguredActionRefIds: preconfiguredActionsScriptedMetric, + actionRefIds: { + multi_terms: { + terms: [ + { + field: 'references.id', + }, + { + field: 'references.name', + }, + ], + }, + }, }, }, - system_actions: { + actions: { nested: { path: 'alert.actions', }, aggs: { - systemActionRefIds: systemActionsScriptedMetric, + actionRefIds: { + multi_terms: { + terms: [ + { + field: 'alert.actions.actionRef', + }, + { + field: 'alert.actions.actionTypeId', + }, + ], + }, + }, }, }, }, }, }); - const aggs = actionResults.aggregations?.refs.actionRefIds.value; + const aggs = getActions(actionResults.aggregations?.refs?.actionRefIds?.buckets); - const preconfiguredActionsAggs = - actionResults.aggregations?.preconfigured_actions?.preconfiguredActionRefIds.value; - - const systemActionsAggs = actionResults.aggregations?.system_actions?.systemActionRefIds.value; + const { preconfiguredActionsAggs, systemActionsAggs } = getInMemoryActions( + actionResults.aggregations?.actions?.actionRefIds?.buckets + ); const totalInMemoryActions = (preconfiguredActionsAggs?.total ?? 0) + (systemActionsAggs?.total ?? 0); @@ -524,40 +456,6 @@ export async function getExecutionsPerDayCount( avgExecutionTimeByType: Record; countRunOutcomeByConnectorType: Record>; }> { - const scriptedMetric = { - scripted_metric: { - init_script: 'state.connectorTypes = [:]; state.total = 0;', - map_script: ` - if (doc['kibana.saved_objects.type'].value == 'action') { - String connectorType = doc['kibana.saved_objects.type_id'].value; - state.connectorTypes.put(connectorType, state.connectorTypes.containsKey(connectorType) ? state.connectorTypes.get(connectorType) + 1 : 1); - state.total++; - } - `, - // Combine script is executed per cluster, but we already have a key-value pair per cluster. - // Despite docs that say this is optional, this script can't be blank. - combine_script: 'return state', - // Reduce script is executed across all clusters, so we need to add up all the total from each cluster - // This also needs to account for having no data - reduce_script: ` - Map connectorTypes = [:]; - long total = 0; - for (state in states) { - if (state !== null) { - total += state.total; - for (String k : state.connectorTypes.keySet()) { - connectorTypes.put(k, connectorTypes.containsKey(k) ? connectorTypes.get(k) + state.connectorTypes.get(k) : state.connectorTypes.get(k)); - } - } - } - Map result = new HashMap(); - result.total = total; - result.connectorTypes = connectorTypes; - return result; - `, - }, - }; - try { const actionResults = await esClient.search({ index: eventLogIndex, @@ -592,7 +490,16 @@ export async function getExecutionsPerDayCount( path: 'kibana.saved_objects', }, aggs: { - byConnectorTypeId: scriptedMetric, + refs: { + filter: { term: { 'kibana.saved_objects.type': 'action' } }, + aggs: { + byConnectorTypeId: { + terms: { + field: 'kibana.saved_objects.type_id', + }, + }, + }, + }, }, }, failedExecutions: { @@ -608,12 +515,21 @@ export async function getExecutionsPerDayCount( }, }, aggs: { - refs: { + actionSavedObjects: { nested: { path: 'kibana.saved_objects', }, aggs: { - byConnectorTypeId: scriptedMetric, + refs: { + filter: { term: { 'kibana.saved_objects.type': 'action' } }, + aggs: { + byConnectorTypeId: { + terms: { + field: 'kibana.saved_objects.type_id', + }, + }, + }, + }, }, }, }, @@ -677,16 +593,22 @@ export async function getExecutionsPerDayCount( }, }); - // @ts-expect-error aggegation type is not specified - const aggsExecutions = actionResults.aggregations.totalExecutions?.byConnectorTypeId.value; + const aggsExecutions = getActionExecutions( + // @ts-expect-error aggegation type is not specified + actionResults.aggregations.totalExecutions?.refs?.byConnectorTypeId.buckets + ); + // convert nanoseconds to milliseconds const aggsAvgExecutionTime = Math.round( // @ts-expect-error aggegation type is not specified actionResults.aggregations.avgDuration.value / (1000 * 1000) ); - const aggsFailedExecutions = + + const aggsFailedExecutions = getActionExecutions( // @ts-expect-error aggegation type is not specified - actionResults.aggregations.failedExecutions?.refs?.byConnectorTypeId.value; + actionResults.aggregations.failedExecutions?.actionSavedObjects?.refs?.byConnectorTypeId + .buckets + ); const avgDurationByType = // @ts-expect-error aggegation type is not specified @@ -714,7 +636,6 @@ export async function getExecutionsPerDayCount( countTotal: aggsExecutions.total, countByType: Object.entries(aggsExecutions.connectorTypes).reduce( (res: Record, [key, value]) => { - // @ts-expect-error aggegation type is not specified res[replaceFirstAndLastDotSymbols(key)] = value; return res; }, @@ -723,7 +644,6 @@ export async function getExecutionsPerDayCount( countFailed: aggsFailedExecutions.total, countFailedByType: Object.entries(aggsFailedExecutions.connectorTypes).reduce( (res: Record, [key, value]) => { - // @ts-expect-error aggegation type is not specified res[replaceFirstAndLastDotSymbols(key)] = value; return res; }, diff --git a/x-pack/plugins/actions/server/usage/lib/actions_telemetry_util.test.ts b/x-pack/plugins/actions/server/usage/lib/actions_telemetry_util.test.ts new file mode 100644 index 0000000000000..f2b222bb695c9 --- /dev/null +++ b/x-pack/plugins/actions/server/usage/lib/actions_telemetry_util.test.ts @@ -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 { + getInMemoryActions, + getActions, + getActionExecutions, + getActionsCount, +} from './actions_telemetry_util'; + +describe('Actions Telemetry Util', () => { + describe('getInMemoryActions', () => { + test('should correctly parse in memory action bucket results', () => { + expect( + getInMemoryActions([ + { + key: ['preconfigured:preconfigured-alert-history-es-index', '.index'], + key_as_string: 'preconfigured:preconfigured-alert-history-es-index|.index', + doc_count: 1, + }, + { + key: ['system_action:test', '.index'], + key_as_string: 'system_action:test|.index', + doc_count: 1, + }, + { + key: ['test:test', '.index'], + key_as_string: 'test:test|.index', + doc_count: 1, + }, + ]) + ).toEqual({ + preconfiguredActionsAggs: { + actionRefs: { + 'preconfigured:preconfigured-alert-history-es-index': { + actionRef: 'preconfigured:preconfigured-alert-history-es-index', + actionTypeId: '.index', + }, + }, + total: 1, + }, + systemActionsAggs: { + actionRefs: { + 'system_action:test': { + actionRef: 'system_action:test', + actionTypeId: '.index', + }, + }, + total: 1, + }, + }); + }); + }); + describe('getActions', () => { + test('should correctly parse action bucket results', () => { + expect( + getActions([ + { + key: ['1', 'action-0'], + key_as_string: '1|action-0', + doc_count: 1, + }, + { + key: ['123', 'action-1'], + key_as_string: '123|action-1', + doc_count: 1, + }, + { + key: ['456', 'action-2'], + key_as_string: '456|action-2', + doc_count: 1, + }, + ]) + ).toEqual({ + connectorIds: { + '1': 'action-0', + '123': 'action-1', + '456': 'action-2', + }, + total: 3, + }); + }); + }); + describe('getActionExecutions', () => { + test('should correctly parse action execution bucket results', () => { + expect( + getActionExecutions([ + { + key: '.server-log', + doc_count: 20, + }, + { + key: '.slack', + doc_count: 100, + }, + ]) + ).toEqual({ + connectorTypes: { + '.server-log': 20, + '.slack': 100, + }, + total: 120, + }); + }); + }); + describe('getActionsCount', () => { + test('should correctly parse action count bucket results', () => { + expect( + getActionsCount([ + { key: '.index', doc_count: 1 }, + { key: '.server-log', doc_count: 3 }, + { key: 'some.type', doc_count: 2 }, + { key: 'another.type.', doc_count: 4 }, + ]) + ).toEqual({ + '.index': 1, + '.server-log': 3, + 'another.type.': 4, + 'some.type': 2, + }); + }); + }); +}); diff --git a/x-pack/plugins/actions/server/usage/lib/actions_telemetry_util.ts b/x-pack/plugins/actions/server/usage/lib/actions_telemetry_util.ts new file mode 100644 index 0000000000000..5241ad38ed399 --- /dev/null +++ b/x-pack/plugins/actions/server/usage/lib/actions_telemetry_util.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + ActionRefIdsAgg, + InMemoryAggRes, + ConnectorAggRes, + ByActionTypeIdAgg, +} from '../actions_telemetry'; + +export function getInMemoryActions(aggregation: ActionRefIdsAgg[] = []) { + const preconfiguredActionsAggs: InMemoryAggRes = { total: 0, actionRefs: {} }; + const systemActionsAggs: InMemoryAggRes = { total: 0, actionRefs: {} }; + for (const a of aggregation) { + const actionRef = a.key[0]; + const actionTypeId = a.key[1]; + if (actionRef.startsWith('preconfigured:')) { + preconfiguredActionsAggs.actionRefs[actionRef] = { actionRef, actionTypeId }; + preconfiguredActionsAggs.total++; + } + if (actionRef.startsWith('system_action:')) { + systemActionsAggs.actionRefs[actionRef] = { actionRef, actionTypeId }; + systemActionsAggs.total++; + } + } + + return { preconfiguredActionsAggs, systemActionsAggs }; +} + +export function getActions(aggregation: ActionRefIdsAgg[] = []) { + const actions: { total: number; connectorIds: Record } = { + total: 0, + connectorIds: {}, + }; + for (const a of aggregation) { + const connectorId = a.key[0]; + const actionRef = a.key[1]; + actions.connectorIds[connectorId] = actionRef; + actions.total++; + } + + return actions; +} + +export function getActionExecutions(aggregation: ByActionTypeIdAgg[] = []) { + const executions: ConnectorAggRes = { total: 0, connectorTypes: {} }; + for (const a of aggregation) { + executions.connectorTypes[a.key] = a.doc_count; + executions.total += a.doc_count; + } + + return executions; +} + +export function getActionsCount(aggregation: ByActionTypeIdAgg[] = []) { + const actions: Record = {}; + for (const a of aggregation) { + actions[a.key] = a.doc_count; + } + + return actions; +} diff --git a/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx b/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx index cf103f4905b20..91e18ea7b4421 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/category_table/category_table.tsx @@ -7,134 +7,73 @@ import type { FC } from 'react'; import React, { useCallback, useMemo, useState } from 'react'; -import moment from 'moment'; import type { EuiBasicTableColumn, EuiTableSelectionType } from '@elastic/eui'; import { useEuiBackgroundColor, EuiInMemoryTable, - EuiHorizontalRule, - EuiSpacer, EuiButtonIcon, EuiToolTip, EuiIcon, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import type { TimefilterContract } from '@kbn/data-plugin/public'; -import type { DataViewField } from '@kbn/data-views-plugin/common'; -import type { Filter } from '@kbn/es-query'; -import { useTableState } from '@kbn/ml-in-memory-table'; -import type { CategorizationAdditionalFilter } from '@kbn/aiops-log-pattern-analysis/create_category_request'; -import { type QueryMode, QUERY_MODE } from '@kbn/aiops-log-pattern-analysis/get_category_query'; +import type { UseTableState } from '@kbn/ml-in-memory-table'; + +import { css } from '@emotion/react'; +import { QUERY_MODE } from '@kbn/aiops-log-pattern-analysis/get_category_query'; import type { Category } from '@kbn/aiops-log-pattern-analysis/types'; import { useEuiTheme } from '../../../hooks/use_eui_theme'; -import type { LogCategorizationAppState } from '../../../application/url_state/log_pattern_analysis'; import { MiniHistogram } from '../../mini_histogram'; -import { useDiscoverLinks, createFilter } from '../use_discover_links'; import type { EventRate } from '../use_categorize_request'; -import { getLabels } from './labels'; -import { TableHeader } from './table_header'; import { ExpandedRow } from './expanded_row'; import { FormattedPatternExamples, FormattedTokens } from '../format_category'; +import type { OpenInDiscover } from './use_open_in_discover'; interface Props { categories: Category[]; eventRate: EventRate; - dataViewId: string; - selectedField: DataViewField | string | undefined; - timefilter: TimefilterContract; - aiopsListState: LogCategorizationAppState; pinnedCategory: Category | null; setPinnedCategory: (category: Category | null) => void; - selectedCategory: Category | null; - setSelectedCategory: (category: Category | null) => void; - onAddFilter?: (values: Filter, alias?: string) => void; - onClose?: () => void; + highlightedCategory: Category | null; + setHighlightedCategory: (category: Category | null) => void; + setSelectedCategories: (category: Category[]) => void; + openInDiscover: OpenInDiscover; + tableState: UseTableState; enableRowActions?: boolean; - additionalFilter?: CategorizationAdditionalFilter; - navigateToDiscover?: boolean; displayExamples?: boolean; } export const CategoryTable: FC = ({ categories, eventRate, - dataViewId, - selectedField, - timefilter, - aiopsListState, pinnedCategory, setPinnedCategory, - selectedCategory, - setSelectedCategory, - onAddFilter, - onClose = () => {}, + highlightedCategory, + setHighlightedCategory, + setSelectedCategories, + openInDiscover, + tableState, enableRowActions = true, - additionalFilter, - navigateToDiscover = true, displayExamples = true, }) => { const euiTheme = useEuiTheme(); const primaryBackgroundColor = useEuiBackgroundColor('primary'); - const { openInDiscoverWithFilter } = useDiscoverLinks(); - const [selectedCategories, setSelectedCategories] = useState([]); - const { onTableChange, pagination, sorting } = useTableState(categories ?? [], 'key'); + const { onTableChange, pagination, sorting } = tableState; + const [itemIdToExpandedRowMap, setItemIdToExpandedRowMap] = useState>( {} ); - const labels = useMemo(() => { - const isFlyout = onAddFilter !== undefined && onClose !== undefined; - return getLabels(isFlyout && navigateToDiscover === false); - }, [navigateToDiscover, onAddFilter, onClose]); - const showSparkline = useMemo(() => { return categories.some((category) => category.sparkline !== undefined); }, [categories]); - const openInDiscover = (mode: QueryMode, category?: Category) => { - if ( - onAddFilter !== undefined && - selectedField !== undefined && - typeof selectedField !== 'string' && - navigateToDiscover === false - ) { - onAddFilter( - createFilter('', selectedField.name, selectedCategories, mode, category), - `Patterns - ${selectedField.name}` - ); - onClose(); - return; - } - - const timefilterActiveBounds = - additionalFilter !== undefined - ? { - min: moment(additionalFilter.from), - max: moment(additionalFilter.to), - } - : timefilter.getActiveBounds(); - - if (timefilterActiveBounds === undefined || selectedField === undefined) { - return; - } - - openInDiscoverWithFilter( - dataViewId, - typeof selectedField === 'string' ? selectedField : selectedField.name, - selectedCategories, - aiopsListState, - timefilterActiveBounds, - mode, - category, - additionalFilter?.field - ); - }; + const { labels: openInDiscoverLabels, openFunction: openInDiscoverFunction } = openInDiscover; const toggleDetails = useCallback( (category: Category) => { @@ -197,20 +136,20 @@ export const CategoryTable: FC = ({ width: '65px', actions: [ { - name: labels.singleSelect.in, - description: labels.singleSelect.in, + name: openInDiscoverLabels.singleSelect.in, + description: openInDiscoverLabels.singleSelect.in, icon: 'plusInCircle', type: 'icon', 'data-test-subj': 'aiopsLogPatternsActionFilterInButton', - onClick: (category) => openInDiscover(QUERY_MODE.INCLUDE, category), + onClick: (category) => openInDiscoverFunction(QUERY_MODE.INCLUDE, category), }, { - name: labels.singleSelect.out, - description: labels.singleSelect.out, + name: openInDiscoverLabels.singleSelect.out, + description: openInDiscoverLabels.singleSelect.out, icon: 'minusInCircle', type: 'icon', 'data-test-subj': 'aiopsLogPatternsActionFilterOutButton', - onClick: (category) => openInDiscover(QUERY_MODE.EXCLUDE, category), + onClick: (category) => openInDiscoverFunction(QUERY_MODE.EXCLUDE, category), }, ], }, @@ -291,7 +230,7 @@ export const CategoryTable: FC = ({ }; } - if (selectedCategory && selectedCategory.key === category.key) { + if (highlightedCategory && highlightedCategory.key === category.key) { return { backgroundColor: euiTheme.euiColorLightestShade, }; @@ -302,49 +241,49 @@ export const CategoryTable: FC = ({ }; }; - return ( - <> - openInDiscover(queryMode)} - /> - - + const tableStyle = css({ + thead: { + position: 'sticky', + insetBlockStart: 0, + zIndex: 1, + backgroundColor: euiTheme.euiColorEmptyShade, + boxShadow: `inset 0 0px 0, inset 0 -1px 0 ${euiTheme.euiBorderColor}`, + }, + }); - - compressed - items={categories} - columns={columns} - selection={selectionValue} - itemId="key" - onTableChange={onTableChange} - pagination={pagination} - sorting={sorting} - data-test-subj="aiopsLogPatternsTable" - itemIdToExpandedRowMap={itemIdToExpandedRowMap} - rowProps={(category) => { - return enableRowActions - ? { - onClick: () => { - if (category.key === pinnedCategory?.key) { - setPinnedCategory(null); - } else { - setPinnedCategory(category); - } - }, - onMouseEnter: () => { - setSelectedCategory(category); - }, - onMouseLeave: () => { - setSelectedCategory(null); - }, - style: getRowStyle(category), - } - : undefined; - }} - /> - + return ( + + compressed + items={categories} + columns={columns} + selection={selectionValue} + itemId="key" + onTableChange={onTableChange} + pagination={pagination} + sorting={sorting} + data-test-subj="aiopsLogPatternsTable" + itemIdToExpandedRowMap={itemIdToExpandedRowMap} + css={tableStyle} + rowProps={(category) => { + return enableRowActions + ? { + onClick: () => { + if (category.key === pinnedCategory?.key) { + setPinnedCategory(null); + } else { + setPinnedCategory(category); + } + }, + onMouseEnter: () => { + setHighlightedCategory(category); + }, + onMouseLeave: () => { + setHighlightedCategory(null); + }, + style: getRowStyle(category), + } + : undefined; + }} + /> ); }; diff --git a/x-pack/plugins/aiops/public/components/log_categorization/category_table/table_header.tsx b/x-pack/plugins/aiops/public/components/log_categorization/category_table/table_header.tsx index 08ac019b8fdc3..d733c050fc3b8 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/category_table/table_header.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/category_table/table_header.tsx @@ -5,76 +5,103 @@ * 2.0. */ -import type { FC } from 'react'; +import type { FC, PropsWithChildren } from 'react'; import React from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiText, EuiButtonEmpty } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiText, EuiButtonEmpty, EuiToolTip } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import { type QueryMode, QUERY_MODE } from '@kbn/aiops-log-pattern-analysis/get_category_query'; +import { QUERY_MODE } from '@kbn/aiops-log-pattern-analysis/get_category_query'; import { useEuiTheme } from '../../../hooks/use_eui_theme'; -import type { getLabels } from './labels'; +import type { OpenInDiscover } from './use_open_in_discover'; interface Props { categoriesCount: number; selectedCategoriesCount: number; - labels: ReturnType; - openInDiscover: (mode: QueryMode) => void; + openInDiscover: OpenInDiscover; } export const TableHeader: FC = ({ categoriesCount, selectedCategoriesCount, - labels, openInDiscover, }) => { const euiTheme = useEuiTheme(); return ( - <> - - - - - {selectedCategoriesCount > 0 ? ( - <> - - - ) : null} - + + + + + {selectedCategoriesCount > 0 ? ( + <> + + + ) : null} + + + {selectedCategoriesCount > 0 ? ( + + - {selectedCategoriesCount > 0 ? ( - <> - - openInDiscover(QUERY_MODE.INCLUDE)} - iconType="plusInCircle" - iconSide="left" - > - {labels.multiSelect.in} - - - - openInDiscover(QUERY_MODE.EXCLUDE)} - iconType="minusInCircle" - iconSide="left" - > - {labels.multiSelect.out} - - - - ) : null} - - + ) : null} + + ); +}; + +export const OpenInDiscoverButtons: FC<{ openInDiscover: OpenInDiscover; showText?: boolean }> = ({ + openInDiscover, + showText = true, +}) => { + const { labels, openFunction } = openInDiscover; + + return ( + + + + openFunction(QUERY_MODE.INCLUDE)} + iconType="plusInCircle" + iconSide="left" + > + {labels.multiSelect.in} + + + + + + openFunction(QUERY_MODE.EXCLUDE)} + iconType="minusInCircle" + iconSide="left" + > + {labels.multiSelect.out} + + + + + ); +}; + +const TooltipWrapper: FC> = ({ + text, + showText, + children, +}) => { + return showText ? ( + <>{children} + ) : ( + + <>{children} + ); }; diff --git a/x-pack/plugins/aiops/public/components/log_categorization/category_table/use_open_in_discover.ts b/x-pack/plugins/aiops/public/components/log_categorization/category_table/use_open_in_discover.ts new file mode 100644 index 0000000000000..963fd6b3a13e8 --- /dev/null +++ b/x-pack/plugins/aiops/public/components/log_categorization/category_table/use_open_in_discover.ts @@ -0,0 +1,100 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useCallback, useMemo } from 'react'; + +import moment from 'moment'; + +import { type QueryMode } from '@kbn/aiops-log-pattern-analysis/get_category_query'; +import type { Filter } from '@kbn/es-query'; +import type { Category } from '@kbn/aiops-log-pattern-analysis/types'; +import type { DataViewField } from '@kbn/data-views-plugin/common'; +import type { TimefilterContract } from '@kbn/data-plugin/public'; +import type { CategorizationAdditionalFilter } from '@kbn/aiops-log-pattern-analysis/create_category_request'; +import { useDiscoverLinks, createFilter } from '../use_discover_links'; +import type { LogCategorizationAppState } from '../../../application/url_state/log_pattern_analysis'; +import { getLabels } from './labels'; + +export interface OpenInDiscover { + openFunction: (mode: QueryMode, category?: Category) => void; + labels: ReturnType; + count: number; +} + +export function useOpenInDiscover( + dataViewId: string, + selectedField: DataViewField | string | undefined, + selectedCategories: Category[], + aiopsListState: LogCategorizationAppState, + timefilter: TimefilterContract, + navigateToDiscover?: boolean, + onAddFilter?: (values: Filter, alias?: string) => void, + additionalFilter?: CategorizationAdditionalFilter, + onClose: () => void = () => {} +): OpenInDiscover { + const { openInDiscoverWithFilter } = useDiscoverLinks(); + + const openFunction = useCallback( + (mode: QueryMode, category?: Category) => { + if ( + onAddFilter !== undefined && + selectedField !== undefined && + typeof selectedField !== 'string' && + navigateToDiscover === false + ) { + onAddFilter( + createFilter('', selectedField.name, selectedCategories, mode, category), + `Patterns - ${selectedField.name}` + ); + onClose(); + return; + } + + const timefilterActiveBounds = + additionalFilter !== undefined + ? { + min: moment(additionalFilter.from), + max: moment(additionalFilter.to), + } + : timefilter.getActiveBounds(); + + if (timefilterActiveBounds === undefined || selectedField === undefined) { + return; + } + + openInDiscoverWithFilter( + dataViewId, + typeof selectedField === 'string' ? selectedField : selectedField.name, + selectedCategories, + aiopsListState, + timefilterActiveBounds, + mode, + category, + additionalFilter?.field + ); + }, + [ + onAddFilter, + selectedField, + navigateToDiscover, + additionalFilter, + timefilter, + openInDiscoverWithFilter, + dataViewId, + selectedCategories, + aiopsListState, + onClose, + ] + ); + + const labels = useMemo(() => { + const isFlyout = onAddFilter !== undefined && onClose !== undefined; + return getLabels(isFlyout && navigateToDiscover === false); + }, [navigateToDiscover, onAddFilter, onClose]); + + return { openFunction, labels, count: selectedCategories.length }; +} diff --git a/x-pack/plugins/aiops/public/components/log_categorization/create_categorization_job.tsx b/x-pack/plugins/aiops/public/components/log_categorization/create_categorization_job.tsx index b0696d8767dc0..91a3185b683bb 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/create_categorization_job.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/create_categorization_job.tsx @@ -9,7 +9,7 @@ import type { FC } from 'react'; import React from 'react'; import moment from 'moment'; -import { EuiButtonEmpty } from '@elastic/eui'; +import { EuiButtonEmpty, EuiButtonIcon, EuiToolTip } from '@elastic/eui'; import type { DataViewField, DataView } from '@kbn/data-views-plugin/common'; import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { @@ -18,6 +18,7 @@ import { } from '@kbn/ml-ui-actions'; import { FormattedMessage } from '@kbn/i18n-react'; +import { i18n } from '@kbn/i18n'; import { useAiopsAppContext } from '../../hooks/use_aiops_app_context'; interface Props { @@ -26,6 +27,7 @@ interface Props { query: QueryDslQueryContainer; earliest: number | undefined; latest: number | undefined; + iconOnly?: boolean; } export const CreateCategorizationJobButton: FC = ({ @@ -34,6 +36,7 @@ export const CreateCategorizationJobButton: FC = ({ query, earliest, latest, + iconOnly = false, }) => { const { uiActions, @@ -58,20 +61,40 @@ export const CreateCategorizationJobButton: FC = ({ return null; } - return ( - <> - - - - + + ); + } + + return ( + + + ); }; diff --git a/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx b/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx index 7cca9f9e8cada..5af9478349642 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/format_category.tsx @@ -95,12 +95,15 @@ export const useCreateFormattedExample = () => { const elements: JSX.Element[] = []; let pos = 0; for (let i = 0; i < positions.length; i++) { + const elementKey = `${key}-token-${i}`; elements.push( - {tempExample.substring(pos, positions[i].start)} + + {tempExample.substring(pos, positions[i].start)} + ); elements.push( - + {tempExample.substring(positions[i].start, positions[i].end)} ); @@ -108,7 +111,7 @@ export const useCreateFormattedExample = () => { } elements.push( - + {tempExample.substring(positions[positions.length - 1].end)} ); @@ -131,10 +134,10 @@ export const FormattedPatternExamples: FC = ({ category, count }) => { .fill(0) .map((_, i) => createFormattedExample(key, examples[i])); return formattedExamples.map((example, i) => ( - <> + {example} {i < formattedExamples.length - 1 ? : null} - + )); }, [category, count, createFormattedExample]); @@ -150,10 +153,19 @@ export const FormattedRegex: FC = ({ category }) => { const elements: JSX.Element[] = []; for (let i = 0; i < regexTokens.length; i++) { const token = regexTokens[i]; + const key = `regex-${i}`; if (token.match(/\.\*\?|\.\+\?/)) { - elements.push({token}); + elements.push( + + {token} + + ); } else { - elements.push({token}); + elements.push( + + {token} + + ); } } return elements; diff --git a/x-pack/plugins/aiops/public/components/log_categorization/information_text.tsx b/x-pack/plugins/aiops/public/components/log_categorization/information_text.tsx index c4fed642b7d0d..5096f42e2082c 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/information_text.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/information_text.tsx @@ -10,93 +10,124 @@ import React from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; import { EuiEmptyPrompt } from '@elastic/eui'; +import type { DataViewField } from '@kbn/data-views-plugin/public'; interface Props { eventRateLength: number; - fieldSelected: boolean; + fields?: DataViewField[]; categoriesLength: number | null; loading: boolean; } export const InformationText: FC = ({ eventRateLength, - fieldSelected, + fields, categoriesLength, loading, }) => { if (loading === true) { return null; } - return ( - <> - {eventRateLength === 0 ? ( - - - - } - titleSize="xs" - body={ -

- -

- } - data-test-subj="aiopsNoWindowParametersEmptyPrompt" - /> - ) : null} - {eventRateLength > 0 && categoriesLength === null ? ( - - - - } - titleSize="xs" - body={ -

- -

- } - data-test-subj="aiopsNoWindowParametersEmptyPrompt" - /> - ) : null} + if (fields?.length === 0) { + return ( + + + + } + titleSize="xs" + body={ +

+ +

+ } + data-test-subj="aiopsNoTextFieldsEmptyPrompt" + /> + ); + } + + if (eventRateLength === 0) { + return ( + + + + } + titleSize="xs" + body={ +

+ +

+ } + data-test-subj="aiopsNoDocsEmptyPrompt" + /> + ); + } + + if (eventRateLength > 0 && categoriesLength === null) { + return ( + + + + } + titleSize="xs" + body={ +

+ +

+ } + data-test-subj="aiopsNoWindowParametersEmptyPrompt" + /> + ); + } + + if (eventRateLength > 0 && categoriesLength !== null && categoriesLength === 0) { + return ( + + + + } + titleSize="xs" + body={ +

+ +

+ } + data-test-subj="aiopsNoCategoriesEmptyPrompt" + /> + ); + } - {eventRateLength > 0 && categoriesLength !== null && categoriesLength === 0 ? ( - - - - } - titleSize="xs" - body={ -

- -

- } - data-test-subj="aiopsNoWindowParametersEmptyPrompt" - /> - ) : null} - - ); + return null; }; diff --git a/x-pack/plugins/aiops/public/components/log_categorization/loading_categorization.tsx b/x-pack/plugins/aiops/public/components/log_categorization/loading_categorization.tsx index cd0e5cd7ad297..1d98325f2d987 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/loading_categorization.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/loading_categorization.tsx @@ -19,26 +19,26 @@ import { import { FormattedMessage } from '@kbn/i18n-react'; interface Props { - onClose: () => void; + onCancel: () => void; } -export const LoadingCategorization: FC = ({ onClose }) => ( +export const LoadingCategorization: FC = ({ onCancel }) => ( <> - + -

+

-

+
@@ -46,7 +46,7 @@ export const LoadingCategorization: FC = ({ onClose }) => ( onClose()} + onClick={() => onCancel()} > Cancel diff --git a/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_enabled.ts b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_enabled.ts new file mode 100644 index 0000000000000..6df61a20f993a --- /dev/null +++ b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_enabled.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { DataView } from '@kbn/data-views-plugin/public'; +import { ES_FIELD_TYPES } from '@kbn/field-types'; +import type { LicensingPluginStart } from '@kbn/licensing-plugin/public'; +import { firstValueFrom } from 'rxjs'; + +export function getPatternAnalysisAvailable(licensing: LicensingPluginStart) { + const lic = firstValueFrom(licensing.license$); + return async (dataView: DataView) => { + const isPlatinum = (await lic).hasAtLeast('platinum'); + return ( + isPlatinum && + dataView.isTimeBased() && + dataView.fields.some((f) => f.esTypes?.includes(ES_FIELD_TYPES.TEXT)) + ); + }; +} diff --git a/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/discover_tabs.tsx b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/discover_tabs.tsx new file mode 100644 index 0000000000000..96fae405eec2c --- /dev/null +++ b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/discover_tabs.tsx @@ -0,0 +1,116 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FC } from 'react'; +import React from 'react'; + +import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; + +import type { Category } from '@kbn/aiops-log-pattern-analysis/types'; +import type { DataViewField, DataView } from '@kbn/data-views-plugin/common'; + +import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import type { OpenInDiscover } from '../category_table/use_open_in_discover'; +import { EmbeddableMenu } from './embeddable_menu'; +import type { RandomSampler } from '../sampling_menu'; +import type { MinimumTimeRangeOption } from './minimum_time_range'; +import { SelectedPatterns } from './selected_patterns'; +import { CreateCategorizationJobButton } from '../create_categorization_job'; +import { SelectedField } from './field_selector'; + +interface Props { + renderViewModeToggle: (patternCount?: number) => React.ReactElement; + randomSampler: RandomSampler; + openInDiscover: OpenInDiscover; + selectedCategories: Category[]; + loadCategories: () => void; + fields: DataViewField[]; + setSelectedField: React.Dispatch>; + selectedField: DataViewField | null; + minimumTimeRangeOption: MinimumTimeRangeOption; + setMinimumTimeRangeOption: (w: MinimumTimeRangeOption) => void; + dataview: DataView; + earliest: number | undefined; + latest: number | undefined; + query: QueryDslQueryContainer; + data: { + categories: Category[]; + displayExamples: boolean; + totalCategories: number; + } | null; +} + +export const DiscoverTabs: FC = ({ + renderViewModeToggle, + randomSampler, + openInDiscover, + selectedCategories, + loadCategories, + fields, + setSelectedField, + selectedField, + minimumTimeRangeOption, + setMinimumTimeRangeOption, + data, + dataview, + earliest, + latest, + query, +}) => { + return ( + + + {renderViewModeToggle(data?.categories.length)} + + + <> + + + {selectedCategories.length > 0 ? ( + + + + ) : null} + + + + +
+
+ loadCategories()} + minimumTimeRangeOption={minimumTimeRangeOption} + setMinimumTimeRangeOption={setMinimumTimeRangeOption} + categoryCount={data?.totalCategories} + /> +
+ {selectedField !== null && earliest !== undefined && latest !== undefined ? ( +
+ +
+ ) : null} +
+
+
+ +
+
+
+ ); +}; diff --git a/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/embeddable_menu.tsx b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/embeddable_menu.tsx new file mode 100644 index 0000000000000..af40e305f558b --- /dev/null +++ b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/embeddable_menu.tsx @@ -0,0 +1,149 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiPopoverTitle, EuiSuperSelect, EuiToolTip } from '@elastic/eui'; +import { EuiFormRow } from '@elastic/eui'; +import { + EuiButtonIcon, + EuiPanel, + EuiPopover, + EuiSpacer, + EuiTitle, + EuiHorizontalRule, + EuiFlexGroup, + EuiFlexItem, + EuiIcon, +} from '@elastic/eui'; +import type { FC } from 'react'; +import React, { useState } from 'react'; +import { i18n } from '@kbn/i18n'; + +import { FormattedMessage } from '@kbn/i18n-react'; +import type { RandomSampler } from '../sampling_menu'; +import { SamplingPanel } from '../sampling_menu/sampling_panel'; +import type { MinimumTimeRangeOption } from './minimum_time_range'; +import { MINIMUM_TIME_RANGE } from './minimum_time_range'; + +interface Props { + randomSampler: RandomSampler; + minimumTimeRangeOption: MinimumTimeRangeOption; + setMinimumTimeRangeOption: (w: MinimumTimeRangeOption) => void; + categoryCount: number | undefined; + reload: () => void; +} + +const minimumTimeRangeOptions = Object.keys(MINIMUM_TIME_RANGE).map((value) => ({ + inputDisplay: value, + value: value as MinimumTimeRangeOption, +})); + +export const EmbeddableMenu: FC = ({ + randomSampler, + minimumTimeRangeOption, + setMinimumTimeRangeOption, + categoryCount, + reload, +}) => { + const [showMenu, setShowMenu] = useState(false); + const togglePopover = () => setShowMenu(!showMenu); + + const button = ( + + togglePopover()} + // @ts-ignore - subdued does work + color="subdued" + aria-label={i18n.translate('xpack.aiops.logCategorization.embeddableMenu.aria', { + defaultMessage: 'Pattern analysis options', + })} + /> + + ); + + return ( + togglePopover()} + panelPaddingSize="s" + anchorPosition="downRight" + > + + + + + + + + + + + {i18n.translate( + 'xpack.aiops.logCategorization.embeddableMenu.minimumTimeRangeOptionsRowLabel', + { + defaultMessage: 'Minimum time range', + } + )} + + + + + + +
+ } + helpText={ + <> + {categoryCount !== undefined && minimumTimeRangeOption !== 'No minimum' ? ( + <> + + + ) : null} + + } + > + + + + + + + + + ); +}; diff --git a/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/field_selector.tsx b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/field_selector.tsx new file mode 100644 index 0000000000000..1941e2d8148d0 --- /dev/null +++ b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/field_selector.tsx @@ -0,0 +1,79 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FC } from 'react'; +import { useMemo } from 'react'; +import { useState } from 'react'; +import React from 'react'; +import { + EuiDataGridToolbarControl, + EuiPopover, + EuiFormRow, + EuiSuperSelect, + EuiFlexGroup, + EuiFlexItem, + EuiToken, +} from '@elastic/eui'; +import type { DataViewField } from '@kbn/data-views-plugin/public'; +import { i18n } from '@kbn/i18n'; + +interface Props { + fields: DataViewField[]; + selectedField: DataViewField | null; + setSelectedField: (field: DataViewField) => void; +} + +export const SelectedField: FC = ({ fields, selectedField, setSelectedField }) => { + const [showPopover, setShowPopover] = useState(false); + const togglePopover = () => setShowPopover(!showPopover); + + const fieldOptions = useMemo( + () => fields.map((field) => ({ inputDisplay: field.name, value: field })), + [fields] + ); + + const button = ( + togglePopover()} + > + + + + + {selectedField?.name} + + + ); + + return ( + setShowPopover(false)} + isOpen={showPopover} + button={button} + className="unifiedDataTableToolbarControlButton" + > + + + + + ); +}; diff --git a/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/index.ts b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/index.ts new file mode 100644 index 0000000000000..8cc8fcbad313a --- /dev/null +++ b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/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 { LogCategorizationEmbeddable } from './log_categorization_for_embeddable'; +export { LogCategorizationWrapper } from './log_categorization_wrapper'; diff --git a/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/log_categorization_for_embeddable.tsx b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/log_categorization_for_embeddable.tsx new file mode 100644 index 0000000000000..1246ea0770004 --- /dev/null +++ b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/log_categorization_for_embeddable.tsx @@ -0,0 +1,463 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { FC } from 'react'; +import React, { useState, useEffect, useCallback, useRef, useMemo } from 'react'; + +import { EuiFlexGroup, EuiFlexItem, EuiSpacer, useEuiPaddingSize } from '@elastic/eui'; + +import type { DataViewField } from '@kbn/data-views-plugin/public'; +import { i18n } from '@kbn/i18n'; +import type { Filter } from '@kbn/es-query'; +import { buildEmptyFilter } from '@kbn/es-query'; +import { usePageUrlState } from '@kbn/ml-url-state'; +import type { FieldValidationResults } from '@kbn/ml-category-validator'; + +import type { Category } from '@kbn/aiops-log-pattern-analysis/types'; + +import type { CategorizationAdditionalFilter } from '@kbn/aiops-log-pattern-analysis/create_category_request'; +import { AIOPS_TELEMETRY_ID } from '@kbn/aiops-common/constants'; +import type { EmbeddablePatternAnalysisInput } from '@kbn/aiops-log-pattern-analysis/embeddable'; +import { css } from '@emotion/react'; +import { useTableState } from '@kbn/ml-in-memory-table/hooks/use_table_state'; +import { + type LogCategorizationPageUrlState, + getDefaultLogCategorizationAppState, +} from '../../../application/url_state/log_pattern_analysis'; +import { createMergedEsQuery } from '../../../application/utils/search_utils'; +import { useData } from '../../../hooks/use_data'; +import { useSearch } from '../../../hooks/use_search'; +import { useAiopsAppContext } from '../../../hooks/use_aiops_app_context'; + +import { useCategorizeRequest } from '../use_categorize_request'; +import type { EventRate } from '../use_categorize_request'; +import { CategoryTable } from '../category_table'; +import { InformationText } from '../information_text'; +import { LoadingCategorization } from '../loading_categorization'; +import { useValidateFieldRequest } from '../use_validate_category_field'; +import { FieldValidationCallout } from '../category_validation_callout'; +import { useMinimumTimeRange } from './use_minimum_time_range'; + +import { createAdditionalConfigHash, createDocumentStatsHash, getMessageField } from '../utils'; +import { useOpenInDiscover } from '../category_table/use_open_in_discover'; +import { DiscoverTabs } from './discover_tabs'; + +export interface LogCategorizationEmbeddableProps { + input: Readonly; + renderViewModeToggle: (patternCount?: number) => React.ReactElement; +} + +const BAR_TARGET = 20; + +export const LogCategorizationEmbeddable: FC = ({ + input, + renderViewModeToggle, +}) => { + const { + notifications: { toasts }, + data: { + query: { getState, filterManager }, + }, + uiSettings, + embeddingOrigin, + } = useAiopsAppContext(); + const tablePadding = useEuiPaddingSize('xs'); + + const { dataView, savedSearch } = input; + + const { runValidateFieldRequest, cancelRequest: cancelValidationRequest } = + useValidateFieldRequest(); + const { + getMinimumTimeRange, + cancelRequest: cancelWiderTimeRangeRequest, + minimumTimeRangeOption, + setMinimumTimeRangeOption, + } = useMinimumTimeRange(); + const { filters, query } = useMemo(() => getState(), [getState]); + + const mounted = useRef(false); + const { + runCategorizeRequest, + cancelRequest: cancelCategorizationRequest, + randomSampler, + } = useCategorizeRequest(); + const [stateFromUrl] = usePageUrlState( + 'logCategorization', + getDefaultLogCategorizationAppState({ + searchQuery: createMergedEsQuery(query, filters, dataView, uiSettings), + }) + ); + const [highlightedCategory, setHighlightedCategory] = useState(null); + const [selectedCategories, setSelectedCategories] = useState([]); + const [selectedField, setSelectedField] = useState(null); + const [fields, setFields] = useState([]); + const [currentDocumentStatsHash, setCurrentDocumentStatsHash] = useState(null); + const [previousDocumentStatsHash, setPreviousDocumentStatsHash] = useState(0); + const [currentAdditionalConfigsHash, setCurrentAdditionalConfigsHash] = useState( + null + ); + const [previousAdditionalConfigsHash, setPreviousAdditionalConfigsHash] = useState( + null + ); + const [loading, setLoading] = useState(null); + const [eventRate, setEventRate] = useState([]); + const [pinnedCategory, setPinnedCategory] = useState(null); + const [data, setData] = useState<{ + categories: Category[]; + displayExamples: boolean; + totalCategories: number; + } | null>(null); + const [fieldValidationResult, setFieldValidationResult] = useState( + null + ); + const tableState = useTableState([], 'key'); + + useEffect( + function initFields() { + setCurrentDocumentStatsHash(null); + setSelectedField(null); + setLoading(null); + const { dataViewFields, messageField } = getMessageField(dataView); + setFields(dataViewFields); + setSelectedField(messageField); + }, + [dataView] + ); + + const cancelRequest = useCallback(() => { + cancelWiderTimeRangeRequest(); + cancelValidationRequest(); + cancelCategorizationRequest(); + }, [cancelCategorizationRequest, cancelValidationRequest, cancelWiderTimeRangeRequest]); + + useEffect( + function cancelRequestOnLeave() { + mounted.current = true; + return () => { + mounted.current = false; + cancelRequest(); + }; + }, + [cancelRequest, mounted] + ); + + const { searchQuery } = useSearch( + { dataView, savedSearch: savedSearch ?? null }, + stateFromUrl, + true + ); + + const { documentStats, timefilter, earliest, latest, intervalMs, forceRefresh } = useData( + dataView, + 'log_categorization', + searchQuery, + () => {}, + undefined, + undefined, + BAR_TARGET, + false + ); + + const onAddFilter = useCallback( + (values: Filter, alias?: string) => { + if (input.switchToDocumentView === undefined) { + return; + } + + const filter = buildEmptyFilter(false, dataView.id); + if (alias) { + filter.meta.alias = alias; + } + filter.query = values.query; + input.switchToDocumentView(); + filterManager.addFilters([filter]); + }, + [dataView.id, filterManager, input] + ); + + const openInDiscover = useOpenInDiscover( + dataView.id!, + selectedField ?? undefined, + selectedCategories, + stateFromUrl, + timefilter, + false, + onAddFilter, + undefined + ); + + useEffect( + function createDocumentStatHash() { + if (documentStats.documentCountStats === undefined) { + return; + } + + const hash = createDocumentStatsHash(documentStats); + if (hash !== previousDocumentStatsHash) { + setCurrentDocumentStatsHash(hash); + setData(null); + setFieldValidationResult(null); + } + }, + [documentStats, previousDocumentStatsHash] + ); + + useEffect( + function createAdditionalConfigHash2() { + if (!selectedField?.name) { + return; + } + + const hash = createAdditionalConfigHash([selectedField.name, minimumTimeRangeOption]); + if (hash !== previousAdditionalConfigsHash) { + setCurrentAdditionalConfigsHash(hash); + setData(null); + setFieldValidationResult(null); + } + }, + [minimumTimeRangeOption, previousAdditionalConfigsHash, selectedField] + ); + + const loadCategories = useCallback(async () => { + const { getIndexPattern, timeFieldName: timeField } = dataView; + const index = getIndexPattern(); + + if ( + loading === true || + selectedField === null || + timeField === undefined || + earliest === undefined || + latest === undefined || + minimumTimeRangeOption === undefined || + mounted.current !== true + ) { + return; + } + + cancelRequest(); + + setLoading(true); + setData(null); + setFieldValidationResult(null); + + const additionalFilter: CategorizationAdditionalFilter = { + from: earliest, + to: latest, + }; + + try { + const timeRange = await getMinimumTimeRange( + index, + timeField, + additionalFilter, + minimumTimeRangeOption, + searchQuery + ); + + if (mounted.current !== true) { + return; + } + + const [validationResult, categorizationResult] = await Promise.all([ + runValidateFieldRequest(index, selectedField.name, timeField, timeRange, searchQuery, { + [AIOPS_TELEMETRY_ID.AIOPS_ANALYSIS_RUN_ORIGIN]: embeddingOrigin, + }), + runCategorizeRequest( + index, + selectedField.name, + timeField, + { to: timeRange.to, from: timeRange.from }, + searchQuery, + intervalMs, + timeRange.useSubAgg ? additionalFilter : undefined + ), + ]); + + if (mounted.current !== true) { + return; + } + + setFieldValidationResult(validationResult); + const { categories, hasExamples } = categorizationResult; + + if (timeRange.useSubAgg) { + const categoriesInBucket = categorizationResult.categories + .map((category) => ({ + ...category, + count: category.subFieldCount ?? category.subTimeRangeCount!, + examples: category.subFieldExamples!, + sparkline: category.subFieldSparkline, + })) + .filter((category) => category.count > 0) + .sort((a, b) => b.count - a.count); + setData({ + categories: categoriesInBucket, + displayExamples: hasExamples, + totalCategories: categories.length, + }); + } else { + setData({ + categories, + displayExamples: hasExamples, + totalCategories: categories.length, + }); + } + } catch (error) { + if (error.name === 'AbortError') { + // ignore error + } else { + toasts.addError(error, { + title: i18n.translate('xpack.aiops.logCategorization.errorLoadingCategories', { + defaultMessage: 'Error loading categories', + }), + }); + } + } + + if (mounted.current === true) { + setLoading(false); + } + }, [ + dataView, + loading, + selectedField, + earliest, + latest, + minimumTimeRangeOption, + cancelRequest, + getMinimumTimeRange, + searchQuery, + runValidateFieldRequest, + embeddingOrigin, + runCategorizeRequest, + intervalMs, + toasts, + ]); + + useEffect( + function triggerAnalysis() { + const buckets = documentStats.documentCountStats?.buckets; + if (buckets === undefined || currentDocumentStatsHash === null) { + return; + } + + if ( + currentDocumentStatsHash !== previousDocumentStatsHash || + (currentAdditionalConfigsHash !== previousAdditionalConfigsHash && + currentDocumentStatsHash !== null) + ) { + randomSampler.setDocCount(documentStats.totalCount); + setEventRate( + Object.entries(buckets).map(([key, docCount]) => ({ + key: +key, + docCount, + })) + ); + loadCategories(); + setPreviousDocumentStatsHash(currentDocumentStatsHash); + setPreviousAdditionalConfigsHash(currentAdditionalConfigsHash); + } + }, + [ + loadCategories, + randomSampler, + previousDocumentStatsHash, + fieldValidationResult, + currentDocumentStatsHash, + currentAdditionalConfigsHash, + documentStats.documentCountStats?.buckets, + documentStats.totalCount, + previousAdditionalConfigsHash, + ] + ); + + useEffect( + function refreshTriggeredFromButton() { + if (input.lastReloadRequestTime !== undefined) { + setPreviousDocumentStatsHash(0); + setPreviousAdditionalConfigsHash(null); + forceRefresh(); + } + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + [input.lastReloadRequestTime] + ); + const style = css({ + overflowY: 'auto', + '.kbnDocTableWrapper': { + overflowX: 'hidden', + }, + }); + + return ( + <> + + + + + + + + <> + + {(loading ?? true) === true ? ( + + ) : null} + + {loading === false && + data !== null && + data.categories.length > 0 && + selectedField !== null ? ( + + ) : null} + + + + + + ); +}; + +// eslint-disable-next-line import/no-default-export +export default LogCategorizationEmbeddable; diff --git a/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/log_categorization_wrapper.tsx b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/log_categorization_wrapper.tsx new file mode 100644 index 0000000000000..49a8219bc880a --- /dev/null +++ b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/log_categorization_wrapper.tsx @@ -0,0 +1,87 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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, { Suspense } from 'react'; +import type { ThemeServiceStart } from '@kbn/core-theme-browser'; +import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; +import type { IUiSettingsClient } from '@kbn/core/public'; +import type { CoreStart } from '@kbn/core/public'; +import type { LensPublicStart } from '@kbn/lens-plugin/public'; +import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; +import type { ChartsPluginStart } from '@kbn/charts-plugin/public'; +import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; +import { DatePickerContextProvider } from '@kbn/ml-date-picker'; +import { StorageContextProvider } from '@kbn/ml-local-storage'; + +import { pick } from 'lodash'; +import { UI_SETTINGS } from '@kbn/data-plugin/public'; +import { Storage } from '@kbn/kibana-utils-plugin/public'; +import { AIOPS_STORAGE_KEYS } from '../../../types/storage'; +import type { AiopsAppDependencies } from '../../../hooks/use_aiops_app_context'; +import { AiopsAppContext } from '../../../hooks/use_aiops_app_context'; +import type { LogCategorizationEmbeddableProps } from './log_categorization_for_embeddable'; +import { LogCategorizationEmbeddable } from './log_categorization_for_embeddable'; + +export interface EmbeddableLogCategorizationDeps { + theme: ThemeServiceStart; + data: DataPublicPluginStart; + uiSettings: IUiSettingsClient; + http: CoreStart['http']; + notifications: CoreStart['notifications']; + i18n: CoreStart['i18n']; + lens: LensPublicStart; + fieldFormats: FieldFormatsStart; + application: CoreStart['application']; + charts: ChartsPluginStart; + uiActions: UiActionsStart; +} + +export interface LogCategorizationEmbeddableWrapperProps { + deps: EmbeddableLogCategorizationDeps; + props: LogCategorizationEmbeddableProps; + embeddingOrigin?: string; +} + +const localStorage = new Storage(window.localStorage); + +export const LogCategorizationWrapper: FC = ({ + deps, + props, + embeddingOrigin, +}) => { + const I18nContext = deps.i18n.Context; + const aiopsAppContextValue = { + embeddingOrigin, + ...deps, + } as unknown as AiopsAppDependencies; + + const datePickerDeps = { + ...pick(deps, ['data', 'http', 'notifications', 'theme', 'uiSettings', 'i18n']), + uiSettingsKeys: UI_SETTINGS, + }; + + return ( + + + + + + + + + + + + ); +}; + +// eslint-disable-next-line import/no-default-export +export default LogCategorizationWrapper; diff --git a/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/minimum_time_range.ts b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/minimum_time_range.ts new file mode 100644 index 0000000000000..07b5485be7bbd --- /dev/null +++ b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/minimum_time_range.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { unitOfTime } from 'moment'; + +export type MinimumTimeRangeOption = 'No minimum' | '1 week' | '1 month' | '3 months' | '6 months'; + +type MinimumTimeRange = Record; + +export const MINIMUM_TIME_RANGE: MinimumTimeRange = { + 'No minimum': { factor: 0, unit: 'w' }, + '1 week': { factor: 1, unit: 'w' }, + '1 month': { factor: 1, unit: 'M' }, + '3 months': { factor: 3, unit: 'M' }, + '6 months': { factor: 6, unit: 'M' }, +}; diff --git a/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/selected_patterns.tsx b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/selected_patterns.tsx new file mode 100644 index 0000000000000..44c9014c1aee1 --- /dev/null +++ b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/selected_patterns.tsx @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { useState } from 'react'; +import React from 'react'; +import { + EuiDataGridToolbarControl, + EuiPopover, + EuiContextMenuPanel, + EuiContextMenuItem, +} from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { QUERY_MODE } from '@kbn/aiops-log-pattern-analysis/get_category_query'; +import type { OpenInDiscover } from '../category_table/use_open_in_discover'; + +export const SelectedPatterns: FC<{ openInDiscover: OpenInDiscover }> = ({ openInDiscover }) => { + const { labels, openFunction } = openInDiscover; + const [showMenu, setShowMenu] = useState(false); + const togglePopover = () => setShowMenu(!showMenu); + + const button = ( + togglePopover()} + badgeContent={openInDiscover.count} + > + + + ); + + return ( + setShowMenu(false)} + isOpen={showMenu} + panelPaddingSize="none" + button={button} + className="unifiedDataTableToolbarControlButton" + > + openFunction(QUERY_MODE.INCLUDE)} + > + {labels.multiSelect.in} + , + openFunction(QUERY_MODE.EXCLUDE)} + > + {labels.multiSelect.out} + , + ]} + /> + + ); +}; diff --git a/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/use_minimum_time_range.ts b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/use_minimum_time_range.ts new file mode 100644 index 0000000000000..e8a47546608da --- /dev/null +++ b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/use_minimum_time_range.ts @@ -0,0 +1,93 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useRef, useCallback } from 'react'; + +import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; +import type { HttpFetchOptions } from '@kbn/core/public'; +import { getTimeFieldRange } from '@kbn/ml-date-picker'; +import moment from 'moment'; +import { useStorage } from '@kbn/ml-local-storage'; +import { useAiopsAppContext } from '../../../hooks/use_aiops_app_context'; +import type { MinimumTimeRangeOption } from './minimum_time_range'; +import { MINIMUM_TIME_RANGE } from './minimum_time_range'; +import type { AiOpsKey, AiOpsStorageMapped } from '../../../types/storage'; +import { AIOPS_PATTERN_ANALYSIS_MINIMUM_TIME_RANGE_PREFERENCE } from '../../../types/storage'; + +export function useMinimumTimeRange() { + const { http } = useAiopsAppContext(); + const abortController = useRef(new AbortController()); + + const getMinimumTimeRange = useCallback( + async ( + index: string, + timeField: string, + timeRange: { from: number; to: number }, + minimumTimeRangeOption: MinimumTimeRangeOption, + queryIn: QueryDslQueryContainer, + headers?: HttpFetchOptions['headers'] + ) => { + const minimumTimeRange = MINIMUM_TIME_RANGE[minimumTimeRangeOption]; + const minimumTimeRangeMs = moment + .duration(minimumTimeRange.factor, minimumTimeRange.unit) + .asMilliseconds(); + const currentMinimumTimeRange = timeRange.to - timeRange.from; + + // the time range is already wide enough + if (currentMinimumTimeRange > minimumTimeRangeMs) { + return { ...timeRange, useSubAgg: false }; + } + + const resp = await getTimeFieldRange({ + http, + index, + timeFieldName: timeField, + query: queryIn, + path: '/internal/file_upload/time_field_range', + signal: abortController.current.signal, + }); + + // the index isn't big enough to get a wider time range + const indexTimeRangeMs = resp.end.epoch - resp.start.epoch; + if (indexTimeRangeMs < minimumTimeRangeMs) { + return { + from: resp.start.epoch, + to: resp.end.epoch, + useSubAgg: true, + }; + } + + const remainder = minimumTimeRangeMs - currentMinimumTimeRange; + const newFrom = Math.max(timeRange.from - remainder, resp.start.epoch); + const newTo = Math.min(newFrom + minimumTimeRangeMs, resp.end.epoch); + + return { + from: newFrom, + to: newTo, + useSubAgg: true, + }; + }, + [http] + ); + + const [minimumTimeRangeOption, setMinimumTimeRangeOption] = useStorage< + AiOpsKey, + AiOpsStorageMapped + >(AIOPS_PATTERN_ANALYSIS_MINIMUM_TIME_RANGE_PREFERENCE, '1 week'); + + const cancelRequest = useCallback(() => { + abortController.current.abort(); + abortController.current = new AbortController(); + }, []); + + return { + getMinimumTimeRange, + cancelRequest, + minimumTimeRangeOption, + setMinimumTimeRangeOption, + }; +} diff --git a/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_flyout.tsx b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_flyout.tsx index b4bcf95129b2b..b68f4d4728daa 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_flyout.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_flyout.tsx @@ -19,20 +19,20 @@ import { EuiSpacer, EuiToolTip, EuiIcon, + EuiHorizontalRule, } from '@elastic/eui'; import type { SavedSearch } from '@kbn/saved-search-plugin/public'; import type { DataView, DataViewField } from '@kbn/data-views-plugin/public'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import type { Filter } from '@kbn/es-query'; -import { buildEmptyFilter } from '@kbn/es-query'; import { usePageUrlState } from '@kbn/ml-url-state'; import type { FieldValidationResults } from '@kbn/ml-category-validator'; import { AIOPS_TELEMETRY_ID } from '@kbn/aiops-common/constants'; import type { CategorizationAdditionalFilter } from '@kbn/aiops-log-pattern-analysis/create_category_request'; import type { Category } from '@kbn/aiops-log-pattern-analysis/types'; +import { useTableState } from '@kbn/ml-in-memory-table/hooks/use_table_state'; import { type LogCategorizationPageUrlState, getDefaultLogCategorizationAppState, @@ -51,6 +51,8 @@ import { LoadingCategorization } from './loading_categorization'; import { useValidateFieldRequest } from './use_validate_category_field'; import { FieldValidationCallout } from './category_validation_callout'; import { CreateCategorizationJobButton } from './create_categorization_job'; +import { TableHeader } from './category_table/table_header'; +import { useOpenInDiscover } from './category_table/use_open_in_discover'; enum SELECTED_TAB { BUCKET, @@ -80,7 +82,7 @@ export const LogCategorizationFlyout: FC = ({ const { notifications: { toasts }, data: { - query: { getState, filterManager }, + query: { getState }, }, uiSettings, } = useAiopsAppContext(); @@ -102,7 +104,8 @@ export const LogCategorizationFlyout: FC = ({ searchQuery: createMergedEsQuery(query, filters, dataView, uiSettings), }) ); - const [selectedCategory, setSelectedCategory] = useState(null); + const [highlightedCategory, setHighlightedCategory] = useState(null); + const [selectedCategories, setSelectedCategories] = useState([]); const [selectedSavedSearch /* , setSelectedSavedSearch*/] = useState(savedSearch); const [loading, setLoading] = useState(true); const [eventRate, setEventRate] = useState([]); @@ -117,6 +120,7 @@ export const LogCategorizationFlyout: FC = ({ ); const [showTabs, setShowTabs] = useState(false); const [selectedTab, setSelectedTab] = useState(SELECTED_TAB.FULL_TIME_RANGE); + const tableState = useTableState([], 'key'); const cancelRequest = useCallback(() => { cancelValidationRequest(); @@ -150,6 +154,17 @@ export const LogCategorizationFlyout: FC = ({ BAR_TARGET ); + const openInDiscover = useOpenInDiscover( + dataView.id!, + selectedField, + selectedCategories, + stateFromUrl, + timefilter, + true, + undefined, + undefined + ); + const loadCategories = useCallback(async () => { const { getIndexPattern, timeFieldName: timeField } = dataView; const index = getIndexPattern(); @@ -243,18 +258,6 @@ export const LogCategorizationFlyout: FC = ({ toasts, ]); - const onAddFilter = useCallback( - (values: Filter, alias?: string) => { - const filter = buildEmptyFilter(false, dataView.id); - if (alias) { - filter.meta.alias = alias; - } - filter.query = values.query; - filterManager.addFilters([filter]); - }, - [dataView, filterManager] - ); - useEffect(() => { if (documentStats.documentCountStats?.buckets) { randomSampler.setDocCount(documentStats.totalCount); @@ -312,12 +315,11 @@ export const LogCategorizationFlyout: FC = ({ /> ) : null} - {loading === true ? : null} + {loading === true ? : null} {loading === false && data !== null && data.categories.length > 0 ? ( <> @@ -388,31 +390,31 @@ export const LogCategorizationFlyout: FC = ({ ) : null} + + + + + ) : null} diff --git a/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_page.tsx b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_page.tsx index 2531a47419dc4..6d8be420fd342 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_page.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_page.tsx @@ -10,6 +10,7 @@ import React, { useState, useEffect, useCallback, useMemo } from 'react'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { EuiComboBoxOptionOption } from '@elastic/eui'; +import { EuiHorizontalRule } from '@elastic/eui'; import { EuiButton, EuiSpacer, @@ -27,10 +28,10 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { usePageUrlState, useUrlState } from '@kbn/ml-url-state'; import type { FieldValidationResults } from '@kbn/ml-category-validator'; import type { SearchQueryLanguage } from '@kbn/ml-query-utils'; -import { stringHash } from '@kbn/ml-string-hash'; import { AIOPS_TELEMETRY_ID } from '@kbn/aiops-common/constants'; import type { Category } from '@kbn/aiops-log-pattern-analysis/types'; +import { useTableState } from '@kbn/ml-in-memory-table/hooks/use_table_state'; import { useDataSource } from '../../hooks/use_data_source'; import { useData } from '../../hooks/use_data'; import { useSearch } from '../../hooks/use_search'; @@ -51,7 +52,9 @@ import { InformationText } from './information_text'; import { SamplingMenu } from './sampling_menu'; import { useValidateFieldRequest } from './use_validate_category_field'; import { FieldValidationCallout } from './category_validation_callout'; -import type { DocumentStats } from '../../hooks/use_document_count_stats'; +import { createDocumentStatsHash } from './utils'; +import { TableHeader } from './category_table/table_header'; +import { useOpenInDiscover } from './category_table/use_open_in_discover'; const BAR_TARGET = 20; const DEFAULT_SELECTED_FIELD = 'message'; @@ -80,7 +83,8 @@ export const LogCategorizationPage: FC = ({ embeddin ); const [globalState, setGlobalState] = useUrlState('_g'); const [selectedField, setSelectedField] = useState(); - const [selectedCategory, setSelectedCategory] = useState(null); + const [highlightedCategory, setHighlightedCategory] = useState(null); + const [selectedCategories, setSelectedCategories] = useState([]); const [selectedSavedSearch, setSelectedSavedSearch] = useState(savedSearch); const [previousDocumentStatsHash, setPreviousDocumentStatsHash] = useState(0); const [loading, setLoading] = useState(false); @@ -94,6 +98,7 @@ export const LogCategorizationPage: FC = ({ embeddin const [fieldValidationResult, setFieldValidationResult] = useState( null ); + const tableState = useTableState([], 'key'); const cancelRequest = useCallback(() => { cancelValidationRequest(); @@ -154,6 +159,17 @@ export const LogCategorizationPage: FC = ({ embeddin BAR_TARGET ); + const openInDiscover = useOpenInDiscover( + dataView.id!, + selectedField, + selectedCategories, + stateFromUrl, + timefilter, + true, + undefined, + undefined + ); + useEffect(() => { if (globalState?.time !== undefined) { timefilter.setTime({ @@ -253,8 +269,6 @@ export const LogCategorizationPage: FC = ({ embeddin docCount, })) ); - setData(null); - setFieldValidationResult(null); setTotalCount(documentStats.totalCount); if (fieldValidationResult !== null) { loadCategories(); @@ -371,7 +385,7 @@ export const LogCategorizationPage: FC = ({ embeddin @@ -387,36 +401,33 @@ export const LogCategorizationPage: FC = ({ embeddin loading={loading} categoriesLength={data?.categories?.length ?? null} eventRateLength={eventRate.length} - fieldSelected={selectedField !== null} /> {selectedField !== undefined && data !== null && data.categories.length > 0 ? ( - + <> + + + + + + + ) : null} ); }; - -/** - * Creates a hash from the document stats to determine if the document stats have changed. - */ -function createDocumentStatsHash(documentStats: DocumentStats) { - const lastTimeStampMs = documentStats.documentCountStats?.lastDocTimeStampMs; - const totalCount = documentStats.documentCountStats?.totalCount; - const times = Object.keys(documentStats.documentCountStats?.buckets ?? {}); - const firstBucketTimeStamp = times.length ? times[0] : undefined; - const lastBucketTimeStamp = times.length ? times[times.length - 1] : undefined; - return stringHash(`${lastTimeStampMs}${totalCount}${firstBucketTimeStamp}${lastBucketTimeStamp}`); -} diff --git a/x-pack/plugins/aiops/public/components/log_categorization/sampling_menu/random_sampler.ts b/x-pack/plugins/aiops/public/components/log_categorization/sampling_menu/random_sampler.ts index dac084c605d82..20b6d25668ba1 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/sampling_menu/random_sampler.ts +++ b/x-pack/plugins/aiops/public/components/log_categorization/sampling_menu/random_sampler.ts @@ -28,27 +28,33 @@ export type RandomSamplerProbability = number | null; export const RANDOM_SAMPLER_SELECT_OPTIONS: Array<{ value: RandomSamplerOption; - text: string; + inputDisplay: string; 'data-test-subj': string; }> = [ { 'data-test-subj': 'aiopsRandomSamplerOptionOnAutomatic', value: RANDOM_SAMPLER_OPTION.ON_AUTOMATIC, - text: i18n.translate('xpack.aiops.logCategorization.randomSamplerPreference.onAutomaticLabel', { - defaultMessage: 'On - automatic', - }), + inputDisplay: i18n.translate( + 'xpack.aiops.logCategorization.randomSamplerPreference.onAutomaticLabel', + { + defaultMessage: 'On - automatic', + } + ), }, { 'data-test-subj': 'aiopsRandomSamplerOptionOnManual', value: RANDOM_SAMPLER_OPTION.ON_MANUAL, - text: i18n.translate('xpack.aiops.logCategorization.randomSamplerPreference.onManualLabel', { - defaultMessage: 'On - manual', - }), + inputDisplay: i18n.translate( + 'xpack.aiops.logCategorization.randomSamplerPreference.onManualLabel', + { + defaultMessage: 'On - manual', + } + ), }, { 'data-test-subj': 'aiopsRandomSamplerOptionOff', value: RANDOM_SAMPLER_OPTION.OFF, - text: i18n.translate('xpack.aiops.logCategorization.randomSamplerPreference.offLabel', { + inputDisplay: i18n.translate('xpack.aiops.logCategorization.randomSamplerPreference.offLabel', { defaultMessage: 'Off', }), }, @@ -126,3 +132,58 @@ export class RandomSampler { return wrapper; } } + +export const randomSamplerText = (randomSamplerPreference: RandomSamplerOption) => { + switch (randomSamplerPreference) { + case RANDOM_SAMPLER_OPTION.OFF: + return { + calloutInfoMessage: i18n.translate( + 'xpack.aiops.logCategorization.randomSamplerSettingsPopUp.offCallout.message', + { + defaultMessage: + 'Random sampling can be turned on to increase analysis speed. Accuracy will slightly decrease.', + } + ), + buttonText: i18n.translate( + 'xpack.aiops.logCategorization.randomSamplerSettingsPopUp.offCallout.button', + { + defaultMessage: 'No sampling', + } + ), + }; + case RANDOM_SAMPLER_OPTION.ON_AUTOMATIC: + return { + calloutInfoMessage: i18n.translate( + 'xpack.aiops.logCategorization.randomSamplerSettingsPopUp.onAutomaticCallout.message', + { + defaultMessage: + 'The pattern analysis will use random sampler aggregations. The probability is automatically set to balance accuracy and speed.', + } + ), + buttonText: i18n.translate( + 'xpack.aiops.logCategorization.randomSamplerSettingsPopUp.onAutomaticCallout.button', + { + defaultMessage: 'Auto sampling', + } + ), + }; + + case RANDOM_SAMPLER_OPTION.ON_MANUAL: + default: + return { + calloutInfoMessage: i18n.translate( + 'xpack.aiops.logCategorization.randomSamplerSettingsPopUp.onManualCallout.message', + { + defaultMessage: + 'The pattern analysis will use random sampler aggregations. A lower percentage probability increases performance, but some accuracy is lost.', + } + ), + buttonText: i18n.translate( + 'xpack.aiops.logCategorization.randomSamplerSettingsPopUp.onManualCallout.button', + { + defaultMessage: 'Manual sampling', + } + ), + }; + } +}; diff --git a/x-pack/plugins/aiops/public/components/log_categorization/sampling_menu/sampling_menu.tsx b/x-pack/plugins/aiops/public/components/log_categorization/sampling_menu/sampling_menu.tsx index 92eeeb0fb0c1e..d2dd9591e76f7 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/sampling_menu/sampling_menu.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/sampling_menu/sampling_menu.tsx @@ -6,24 +6,14 @@ */ import type { FC } from 'react'; -import React, { useCallback, useMemo, useState } from 'react'; -import { - EuiFlexItem, - EuiPopover, - EuiPanel, - EuiSpacer, - EuiCallOut, - EuiSelect, - EuiFormRow, - EuiButtonEmpty, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n-react'; -import useObservable from 'react-use/lib/useObservable'; +import { useMemo } from 'react'; +import React, { useState } from 'react'; +import { EuiPopover, EuiButtonEmpty, EuiPanel } from '@elastic/eui'; -import { RandomSamplerRangeSlider } from './random_sampler_range_slider'; -import type { RandomSampler, RandomSamplerOption } from './random_sampler'; -import { RANDOM_SAMPLER_OPTION, RANDOM_SAMPLER_SELECT_OPTIONS } from './random_sampler'; +import useObservable from 'react-use/lib/useObservable'; +import type { RandomSampler } from './random_sampler'; +import { randomSamplerText } from './random_sampler'; +import { SamplingPanel } from './sampling_panel'; interface Props { randomSampler: RandomSampler; @@ -33,82 +23,12 @@ interface Props { export const SamplingMenu: FC = ({ randomSampler, reload }) => { const [showSamplingOptionsPopover, setShowSamplingOptionsPopover] = useState(false); - const samplingProbability = useObservable( - randomSampler.getProbability$(), - randomSampler.getProbability() - ); - const setSamplingProbability = useCallback( - (probability: number | null) => { - randomSampler.setProbability(probability); - reload(); - }, - [reload, randomSampler] - ); - const randomSamplerPreference = useObservable(randomSampler.getMode$(), randomSampler.getMode()); - const setRandomSamplerPreference = useCallback( - (mode: RandomSamplerOption) => { - randomSampler.setMode(mode); - reload(); - }, - [randomSampler, reload] + const { buttonText } = useMemo( + () => randomSamplerText(randomSamplerPreference), + [randomSamplerPreference] ); - const { calloutInfoMessage, buttonText } = useMemo(() => { - switch (randomSamplerPreference) { - case RANDOM_SAMPLER_OPTION.OFF: - return { - calloutInfoMessage: i18n.translate( - 'xpack.aiops.logCategorization.randomSamplerSettingsPopUp.offCallout.message', - { - defaultMessage: - 'Random sampling can be turned on to increase the speed of analysis, although some accuracy will be lost.', - } - ), - buttonText: i18n.translate( - 'xpack.aiops.logCategorization.randomSamplerSettingsPopUp.offCallout.button', - { - defaultMessage: 'No sampling', - } - ), - }; - case RANDOM_SAMPLER_OPTION.ON_AUTOMATIC: - return { - calloutInfoMessage: i18n.translate( - 'xpack.aiops.logCategorization.randomSamplerSettingsPopUp.onAutomaticCallout.message', - { - defaultMessage: - 'The pattern analysis will use random sampler aggregations. The probability is automatically set to balance accuracy and speed.', - } - ), - buttonText: i18n.translate( - 'xpack.aiops.logCategorization.randomSamplerSettingsPopUp.onAutomaticCallout.button', - { - defaultMessage: 'Auto sampling', - } - ), - }; - - case RANDOM_SAMPLER_OPTION.ON_MANUAL: - default: - return { - calloutInfoMessage: i18n.translate( - 'xpack.aiops.logCategorization.randomSamplerSettingsPopUp.onManualCallout.message', - { - defaultMessage: - 'The pattern analysis will use random sampler aggregations. A lower percentage probability increases performance, but some accuracy is lost.', - } - ), - buttonText: i18n.translate( - 'xpack.aiops.logCategorization.randomSamplerSettingsPopUp.onManualCallout.button', - { - defaultMessage: 'Manual sampling', - } - ), - }; - } - }, [randomSamplerPreference]); - return ( = ({ randomSampler, reload }) => { anchorPosition="downLeft" > - - - - - - - setRandomSamplerPreference(e.target.value as RandomSamplerOption)} - /> - - - {randomSamplerPreference === RANDOM_SAMPLER_OPTION.ON_MANUAL ? ( - - ) : null} - - {randomSamplerPreference === RANDOM_SAMPLER_OPTION.ON_AUTOMATIC ? ( - - ) : null} + ); }; - -const ProbabilityUsedMessage: FC<{ samplingProbability: number | null }> = ({ - samplingProbability, -}) => { - return samplingProbability !== null ? ( -
- - - -
- ) : null; -}; diff --git a/x-pack/plugins/aiops/public/components/log_categorization/sampling_menu/sampling_panel.tsx b/x-pack/plugins/aiops/public/components/log_categorization/sampling_menu/sampling_panel.tsx new file mode 100644 index 0000000000000..1944039a85e7f --- /dev/null +++ b/x-pack/plugins/aiops/public/components/log_categorization/sampling_menu/sampling_panel.tsx @@ -0,0 +1,124 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FC } from 'react'; +import React, { useCallback, useMemo } from 'react'; +import { EuiSpacer, EuiCallOut, EuiFormRow, EuiSuperSelect } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; +import useObservable from 'react-use/lib/useObservable'; + +import { RandomSamplerRangeSlider } from './random_sampler_range_slider'; +import type { RandomSampler, RandomSamplerOption } from './random_sampler'; +import { randomSamplerText } from './random_sampler'; +import { RANDOM_SAMPLER_OPTION, RANDOM_SAMPLER_SELECT_OPTIONS } from './random_sampler'; + +interface Props { + randomSampler: RandomSampler; + calloutPosition?: 'top' | 'bottom'; + reload: () => void; +} + +export const SamplingPanel: FC = ({ randomSampler, reload, calloutPosition = 'top' }) => { + const samplingProbability = useObservable( + randomSampler.getProbability$(), + randomSampler.getProbability() + ); + const setSamplingProbability = useCallback( + (probability: number | null) => { + randomSampler.setProbability(probability); + reload(); + }, + [reload, randomSampler] + ); + + const randomSamplerPreference = useObservable(randomSampler.getMode$(), randomSampler.getMode()); + const setRandomSamplerPreference = useCallback( + (mode: RandomSamplerOption) => { + randomSampler.setMode(mode); + reload(); + }, + [randomSampler, reload] + ); + + const { calloutInfoMessage } = useMemo( + () => randomSamplerText(randomSamplerPreference), + [randomSamplerPreference] + ); + + return ( + <> + {calloutPosition === 'top' ? ( + + ) : null} + + + ) : null + } + > + + + + {randomSamplerPreference === RANDOM_SAMPLER_OPTION.ON_MANUAL ? ( + + ) : null} + + {calloutPosition === 'bottom' ? ( + + ) : null} + + ); +}; + +const ProbabilityUsedMessage: FC<{ samplingProbability: number | null }> = ({ + samplingProbability, +}) => { + return samplingProbability !== null ? ( +
+ +
+ ) : null; +}; + +const CalloutInfoMessage: FC<{ + calloutInfoMessage: string; + calloutPosition: 'top' | 'bottom'; +}> = ({ calloutInfoMessage, calloutPosition }) => ( + <> + {calloutPosition === 'bottom' ? : null} + + {calloutPosition === 'top' ? : null} + +); diff --git a/x-pack/plugins/aiops/public/components/log_categorization/use_categorize_request.ts b/x-pack/plugins/aiops/public/components/log_categorization/use_categorize_request.ts index 9fb050699e422..9008e9100d50b 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/use_categorize_request.ts +++ b/x-pack/plugins/aiops/public/components/log_categorization/use_categorize_request.ts @@ -85,7 +85,9 @@ export function useCategorizeRequest() { query, wrap, intervalMs, - additionalFilter + additionalFilter, + true, + additionalFilter === undefined // don't include the outer sparkline if there is an additional filter ), { abortSignal: abortController.current.signal } ) diff --git a/x-pack/plugins/aiops/public/components/log_categorization/use_validate_category_field.ts b/x-pack/plugins/aiops/public/components/log_categorization/use_validate_category_field.ts index b2e16363aba35..e771a981a9c49 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/use_validate_category_field.ts +++ b/x-pack/plugins/aiops/public/components/log_categorization/use_validate_category_field.ts @@ -51,6 +51,7 @@ export function useValidateFieldRequest() { }), headers, version: '1', + signal: abortController.current.signal, } ); diff --git a/x-pack/plugins/aiops/public/components/log_categorization/utils.ts b/x-pack/plugins/aiops/public/components/log_categorization/utils.ts new file mode 100644 index 0000000000000..152cd56b77593 --- /dev/null +++ b/x-pack/plugins/aiops/public/components/log_categorization/utils.ts @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { stringHash } from '@kbn/ml-string-hash'; +import type { DataView, DataViewField } from '@kbn/data-views-plugin/public'; +import { ES_FIELD_TYPES } from '@kbn/field-types'; +import type { DocumentStats } from '../../hooks/use_document_count_stats'; + +/** + * Creates a hash from the document stats to determine if the document stats have changed. + */ +export function createDocumentStatsHash(documentStats: DocumentStats) { + const lastTimeStampMs = documentStats.documentCountStats?.lastDocTimeStampMs; + const totalCount = documentStats.documentCountStats?.totalCount; + const times = Object.keys(documentStats.documentCountStats?.buckets ?? {}); + const firstBucketTimeStamp = times.length ? times[0] : undefined; + const lastBucketTimeStamp = times.length ? times[times.length - 1] : undefined; + + return stringHash(`${lastTimeStampMs}${totalCount}${firstBucketTimeStamp}${lastBucketTimeStamp}`); +} + +export function createAdditionalConfigHash(additionalStrings: string[] = []) { + return stringHash(`${additionalStrings.join('')}`); +} + +/** + * Retrieves the message field from a DataView object. + * If the message field is not found, it falls back to error.message or event.original or the first text field in the DataView. + * + * @param dataView - The DataView object containing the fields. + * @returns An object containing the message field and all the fields in the DataView. + */ +export function getMessageField(dataView: DataView): { + messageField: DataViewField | null; + dataViewFields: DataViewField[]; +} { + const dataViewFields = dataView.fields.filter((f) => f.esTypes?.includes(ES_FIELD_TYPES.TEXT)); + + let messageField: DataViewField | null | undefined = dataViewFields.find( + (f) => f.name === 'message' + ); + if (messageField === undefined) { + messageField = dataViewFields.find((f) => f.name === 'error.message'); + } + if (messageField === undefined) { + messageField = dataViewFields.find((f) => f.name === 'event.original'); + } + if (messageField === undefined) { + if (dataViewFields.length > 0) { + messageField = dataViewFields[0]; + } else { + messageField = null; + } + } + return { messageField, dataViewFields }; +} diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content.tsx index 59373ae4b9253..f017011596473 100644 --- a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content.tsx +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content.tsx @@ -63,6 +63,7 @@ export function getDocumentCountStatsSplitLabel( } export interface LogRateAnalysisContentProps { + /** Optional time range override */ timeRange?: { min: Moment; max: Moment }; /** Elasticsearch query to pass to analysis endpoint */ esSearchQuery?: estypes.QueryDslQueryContainer; @@ -151,6 +152,7 @@ export const LogRateAnalysisContent: FC = ({ currentSelectedSignificantItem, currentSelectedGroup, undefined, + true, timeRange ); diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_page.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_page.tsx index c8d69b54e70a6..f6a40f2540f65 100644 --- a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_page.tsx +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_page.tsx @@ -99,7 +99,7 @@ export const LogRateAnalysisPage: FC = ({ stickyHistogram }) => { ); useEffect( - // TODO: Consolidate this hook/function with with Data visualizer's + // TODO: Consolidate this hook/function with the one in `x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/index_data_visualizer_view/index_data_visualizer_view.tsx` function clearFiltersOnLeave() { return () => { // We want to clear all filters that have not been pinned globally diff --git a/x-pack/plugins/aiops/public/hooks/use_data.ts b/x-pack/plugins/aiops/public/hooks/use_data.ts index 9986a4d65dd70..5c7acaf2b2372 100644 --- a/x-pack/plugins/aiops/public/hooks/use_data.ts +++ b/x-pack/plugins/aiops/public/hooks/use_data.ts @@ -36,6 +36,7 @@ export const useData = ( selectedSignificantItem?: SignificantItem, selectedGroup: GroupTableItem | null = null, barTarget: number = DEFAULT_BAR_TARGET, + changePointsByDefault = true, timeRange?: { min: Moment; max: Moment } ) => { const { executionContext, uiSettings } = useAiopsAppContext(); @@ -103,7 +104,8 @@ export const useData = ( const documentStats = useDocumentCountStats( overallStatsRequest, selectedSignificantItemStatsRequest, - lastRefresh + lastRefresh, + changePointsByDefault ); useEffect(() => { @@ -111,14 +113,17 @@ export const useData = ( timefilter.getAutoRefreshFetch$(), timefilter.getTimeUpdate$(), mlTimefilterRefresh$ - ).subscribe(() => { + ).subscribe((done) => { if (onUpdate) { onUpdate({ time: timefilter.getTime(), refreshInterval: timefilter.getRefreshInterval(), }); - setLastRefresh(Date.now()); + if (typeof done === 'function') { + done(); + } } + setLastRefresh(Date.now()); }); // This listens just for an initial update of the timefilter to be switched on. diff --git a/x-pack/plugins/aiops/public/hooks/use_document_count_stats.ts b/x-pack/plugins/aiops/public/hooks/use_document_count_stats.ts index f431179cfe858..83f10a4a445d3 100644 --- a/x-pack/plugins/aiops/public/hooks/use_document_count_stats.ts +++ b/x-pack/plugins/aiops/public/hooks/use_document_count_stats.ts @@ -56,7 +56,8 @@ function displayError(toastNotifications: ToastsStart, index: string, err: any) export function useDocumentCountStats( searchParams: TParams | undefined, searchParamsCompare: TParams | undefined, - lastRefresh: number + lastRefresh: number, + changePointsByDefault = true ): DocumentStats { const { data, @@ -96,7 +97,7 @@ export function useDocumentCountStats { + const { getPatternAnalysisAvailable } = await import( + './components/log_categorization/log_categorization_enabled' + ); + return getPatternAnalysisAvailable(plugins.licensing); + }, + PatternAnalysisComponent: dynamic( + async () => + import( + './components/log_categorization/log_categorization_for_embeddable/log_categorization_wrapper' + ) + ), }; } diff --git a/x-pack/plugins/aiops/public/types.ts b/x-pack/plugins/aiops/public/types/index.ts old mode 100755 new mode 100644 similarity index 80% rename from x-pack/plugins/aiops/public/types.ts rename to x-pack/plugins/aiops/public/types/index.ts index e4a97bb01f18e..5c71a63bba354 --- a/x-pack/plugins/aiops/public/types.ts +++ b/x-pack/plugins/aiops/public/types/index.ts @@ -18,7 +18,10 @@ import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/ import type { EmbeddableSetup, EmbeddableStart } from '@kbn/embeddable-plugin/public'; import type { CasesPublicSetup } from '@kbn/cases-plugin/public'; import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public'; -import type { ChangePointDetectionSharedComponent } from './shared_components'; +import type { DataView } from '@kbn/data-views-plugin/public'; +import type { ChangePointDetectionSharedComponent } from '../shared_components'; + +import type { LogCategorizationEmbeddableWrapperProps } from '../components/log_categorization/log_categorization_for_embeddable/log_categorization_wrapper'; export interface AiopsPluginSetupDeps { embeddable: EmbeddableSetup; @@ -45,5 +48,7 @@ export interface AiopsPluginStartDeps { export type AiopsPluginSetup = void; export interface AiopsPluginStart { + getPatternAnalysisAvailable: () => Promise<(dataView: DataView) => Promise>; + PatternAnalysisComponent: React.ComponentType; ChangePointDetectionComponent: ChangePointDetectionSharedComponent; } diff --git a/x-pack/plugins/aiops/public/types/storage.ts b/x-pack/plugins/aiops/public/types/storage.ts index e6a1f8d46730b..ea6fde6b06552 100644 --- a/x-pack/plugins/aiops/public/types/storage.ts +++ b/x-pack/plugins/aiops/public/types/storage.ts @@ -6,6 +6,8 @@ */ import { type FrozenTierPreference } from '@kbn/ml-date-picker'; +import type { MinimumTimeRangeOption } from '../components/log_categorization/log_categorization_for_embeddable/minimum_time_range'; + import { type RandomSamplerOption, type RandomSamplerProbability, @@ -15,11 +17,14 @@ export const AIOPS_FROZEN_TIER_PREFERENCE = 'aiops.frozenDataTierPreference'; export const AIOPS_RANDOM_SAMPLING_MODE_PREFERENCE = 'aiops.randomSamplingModePreference'; export const AIOPS_RANDOM_SAMPLING_PROBABILITY_PREFERENCE = 'aiops.randomSamplingProbabilityPreference'; +export const AIOPS_PATTERN_ANALYSIS_MINIMUM_TIME_RANGE_PREFERENCE = + 'aiops.patternAnalysisMinimumTimeRangePreference'; export type AiOps = Partial<{ [AIOPS_FROZEN_TIER_PREFERENCE]: FrozenTierPreference; [AIOPS_RANDOM_SAMPLING_MODE_PREFERENCE]: RandomSamplerOption; [AIOPS_RANDOM_SAMPLING_PROBABILITY_PREFERENCE]: number; + [AIOPS_PATTERN_ANALYSIS_MINIMUM_TIME_RANGE_PREFERENCE]: MinimumTimeRangeOption; }> | null; export type AiOpsKey = keyof Exclude; @@ -30,10 +35,13 @@ export type AiOpsStorageMapped = T extends typeof AIOPS_FROZ ? RandomSamplerOption : T extends typeof AIOPS_RANDOM_SAMPLING_PROBABILITY_PREFERENCE ? RandomSamplerProbability + : T extends typeof AIOPS_PATTERN_ANALYSIS_MINIMUM_TIME_RANGE_PREFERENCE + ? MinimumTimeRangeOption : null; export const AIOPS_STORAGE_KEYS = [ AIOPS_FROZEN_TIER_PREFERENCE, AIOPS_RANDOM_SAMPLING_MODE_PREFERENCE, AIOPS_RANDOM_SAMPLING_PROBABILITY_PREFERENCE, + AIOPS_PATTERN_ANALYSIS_MINIMUM_TIME_RANGE_PREFERENCE, ] as const; diff --git a/x-pack/plugins/aiops/server/routes/log_rate_analysis/analysis_handlers/index_info_handler.ts b/x-pack/plugins/aiops/server/routes/log_rate_analysis/analysis_handlers/index_info_handler.ts index 730b11cdd28a5..038fc0588f6a2 100644 --- a/x-pack/plugins/aiops/server/routes/log_rate_analysis/analysis_handlers/index_info_handler.ts +++ b/x-pack/plugins/aiops/server/routes/log_rate_analysis/analysis_handlers/index_info_handler.ts @@ -36,6 +36,7 @@ export const indexInfoHandlerFactory = let fieldCandidatesCount = fieldCandidates.length; const textFieldCandidates: string[] = []; + let textFieldCandidatesCount = textFieldCandidates.length; let zeroDocsFallback = false; @@ -68,6 +69,7 @@ export const indexInfoHandlerFactory = fieldCandidates.push(...indexInfo.fieldCandidates); fieldCandidatesCount = fieldCandidates.length; textFieldCandidates.push(...indexInfo.textFieldCandidates); + textFieldCandidatesCount = textFieldCandidates.length; zeroDocsFallback = indexInfo.zeroDocsFallback; } catch (e) { if (!isRequestAbortedError(e)) { @@ -92,7 +94,7 @@ export const indexInfoHandlerFactory = defaultMessage: 'Identified {fieldCandidatesCount, plural, one {# field candidate} other {# field candidates}}.', values: { - fieldCandidatesCount, + fieldCandidatesCount: fieldCandidatesCount + textFieldCandidatesCount, }, } ), 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 aa2aa1944e64a..6a3a83352ca76 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 @@ -18,9 +18,9 @@ import type { AiopsLogRateAnalysisApiVersion as ApiVersion, } from '@kbn/aiops-log-rate-analysis/api/schema'; 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,6 +29,20 @@ 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, @@ -47,6 +61,7 @@ export const significantItemsHandlerFactory = textFieldCandidates: string[]; }) => { let fieldCandidatesCount = fieldCandidates.length; + const textFieldCandidatesCount = textFieldCandidates.length; // This will store the combined count of detected significant log patterns and keywords let fieldValuePairsCount = 0; @@ -59,25 +74,6 @@ export const significantItemsHandlerFactory = ) ?? []) ); - // Get significant categories of text fields - if (textFieldCandidates.length > 0) { - significantCategories.push( - ...(await fetchSignificantCategories( - client, - requestBody, - textFieldCandidates, - logger, - stateHandler.sampleProbability(), - responseStream.pushError, - abortSignal - )) - ); - - if (significantCategories.length > 0) { - responseStream.push(addSignificantItemsAction(significantCategories)); - } - } - const significantTerms: SignificantItem[] = []; significantTerms.push( @@ -105,39 +101,67 @@ export const significantItemsHandlerFactory = logDebugMessage('Fetch p-values.'); - const pValuesQueue = queue(async function (fieldCandidate: string) { - stateHandler.loaded((1 / fieldCandidatesCount) * loadingStepSizePValues, false); + const loadingStep = + (1 / (fieldCandidatesCount + textFieldCandidatesCount)) * loadingStepSizePValues; + + const pValuesQueue = queue(async function (payload: Candidate) { + if (isFieldCandidate(payload)) { + const { fieldCandidate } = payload; + let pValues: Awaited>; + + try { + pValues = await fetchSignificantTermPValues( + client, + requestBody, + [fieldCandidate], + logger, + stateHandler.sampleProbability(), + responseStream.pushError, + abortSignal + ); + } catch (e) { + if (!isRequestAbortedError(e)) { + logger.error( + `Failed to fetch p-values for '${fieldCandidate}', got: \n${e.toString()}` + ); + responseStream.pushError(`Failed to fetch p-values for '${fieldCandidate}'.`); + } + return; + } + + remainingFieldCandidates = remainingFieldCandidates.filter((d) => d !== fieldCandidate); - let pValues: Awaited>; + if (pValues.length > 0) { + pValues.forEach((d) => { + fieldsToSample.add(d.fieldName); + }); + significantTerms.push(...pValues); + + responseStream.push(addSignificantItemsAction(pValues)); + + fieldValuePairsCount += pValues.length; + } + } else if (isTextFieldCandidate(payload)) { + const { textFieldCandidate } = payload; - try { - pValues = await fetchSignificantTermPValues( + const significantCategoriesForField = await fetchSignificantCategories( client, requestBody, - [fieldCandidate], + [textFieldCandidate], logger, stateHandler.sampleProbability(), responseStream.pushError, abortSignal ); - } catch (e) { - if (!isRequestAbortedError(e)) { - logger.error(`Failed to fetch p-values for '${fieldCandidate}', got: \n${e.toString()}`); - responseStream.pushError(`Failed to fetch p-values for '${fieldCandidate}'.`); + + if (significantCategoriesForField.length > 0) { + significantCategories.push(...significantCategoriesForField); + responseStream.push(addSignificantItemsAction(significantCategoriesForField)); + fieldValuePairsCount += significantCategoriesForField.length; } - return; } - remainingFieldCandidates = remainingFieldCandidates.filter((d) => d !== fieldCandidate); - - if (pValues.length > 0) { - pValues.forEach((d) => { - fieldsToSample.add(d.fieldName); - }); - significantTerms.push(...pValues); - - responseStream.push(addSignificantItemsAction(pValues)); - } + stateHandler.loaded(loadingStep, false); responseStream.push( updateLoadingStateAction({ @@ -158,18 +182,24 @@ export const significantItemsHandlerFactory = ); }, MAX_CONCURRENT_QUERIES); - pValuesQueue.push(fieldCandidates, (err) => { - if (err) { - logger.error(`Failed to fetch p-values.', got: \n${err.toString()}`); - responseStream.pushError(`Failed to fetch p-values.`); - pValuesQueue.kill(); - responseStream.end(); - } else if (stateHandler.shouldStop()) { - logDebugMessage('shouldStop fetching p-values.'); - pValuesQueue.kill(); - responseStream.end(); + pValuesQueue.push( + [ + ...textFieldCandidates.map((d) => ({ textFieldCandidate: d })), + ...fieldCandidates.map((d) => ({ fieldCandidate: d })), + ], + (err) => { + if (err) { + logger.error(`Failed to fetch p-values.', got: \n${err.toString()}`); + responseStream.pushError(`Failed to fetch p-values.`); + pValuesQueue.kill(); + responseStream.end(); + } else if (stateHandler.shouldStop()) { + logDebugMessage('shouldStop fetching p-values.'); + pValuesQueue.kill(); + responseStream.end(); + } } - }); + ); await pValuesQueue.drain(); fieldValuePairsCount = significantCategories.length + significantTerms.length; diff --git a/x-pack/plugins/aiops/tsconfig.json b/x-pack/plugins/aiops/tsconfig.json index 950caae7fd88c..c4e7af826c0c3 100644 --- a/x-pack/plugins/aiops/tsconfig.json +++ b/x-pack/plugins/aiops/tsconfig.json @@ -11,14 +11,28 @@ "types/**/*" ], "kbn_references": [ - "@kbn/aiops-components", + "@kbn/aiops-change-point-detection", "@kbn/aiops-common", + "@kbn/aiops-components", + "@kbn/aiops-log-pattern-analysis", + "@kbn/aiops-log-rate-analysis", + "@kbn/aiops-test-utils", + "@kbn/analytics", + "@kbn/cases-plugin", "@kbn/charts-plugin", + "@kbn/content-management-utils", "@kbn/core-execution-context-browser", + "@kbn/core-http-server", + "@kbn/core-lifecycle-browser", + "@kbn/core-theme-browser", + "@kbn/core-ui-settings-browser-mocks", "@kbn/core", "@kbn/data-plugin", + "@kbn/data-service", "@kbn/data-views-plugin", "@kbn/datemath", + "@kbn/ebt-tools", + "@kbn/embeddable-plugin", "@kbn/es-query", "@kbn/field-formats-plugin", "@kbn/field-types", @@ -44,38 +58,25 @@ "@kbn/ml-response-stream", "@kbn/ml-route-utils", "@kbn/ml-string-hash", + "@kbn/ml-time-buckets", + "@kbn/ml-ui-actions", "@kbn/ml-url-state", + "@kbn/presentation-containers", + "@kbn/presentation-publishing", + "@kbn/presentation-util-plugin", + "@kbn/react-kibana-context-render", + "@kbn/react-kibana-context-theme", + "@kbn/react-kibana-mount", "@kbn/rison", "@kbn/saved-search-plugin", + "@kbn/search-types", "@kbn/share-plugin", + "@kbn/shared-ux-utility", "@kbn/ui-actions-plugin", "@kbn/unified-field-list", "@kbn/unified-search-plugin", - "@kbn/utility-types", - "@kbn/presentation-util-plugin", - "@kbn/embeddable-plugin", - "@kbn/core-lifecycle-browser", - "@kbn/cases-plugin", - "@kbn/react-kibana-mount", "@kbn/usage-collection-plugin", - "@kbn/analytics", - "@kbn/ml-ui-actions", - "@kbn/core-http-server", - "@kbn/core-ui-settings-browser-mocks", - "@kbn/ml-time-buckets", - "@kbn/ebt-tools", - "@kbn/aiops-test-utils", - "@kbn/aiops-log-rate-analysis", - "@kbn/aiops-log-pattern-analysis", - "@kbn/aiops-change-point-detection", - "@kbn/react-kibana-context-theme", - "@kbn/react-kibana-context-render", - "@kbn/presentation-publishing", - "@kbn/data-service", - "@kbn/shared-ux-utility", - "@kbn/presentation-containers", - "@kbn/search-types", - "@kbn/content-management-utils", + "@kbn/utility-types", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/alerting/common/routes/rule/apis/create/schemas/v1.ts b/x-pack/plugins/alerting/common/routes/rule/apis/create/schemas/v1.ts index 40dd30249c09d..cb24fe674b899 100644 --- a/x-pack/plugins/alerting/common/routes/rule/apis/create/schemas/v1.ts +++ b/x-pack/plugins/alerting/common/routes/rule/apis/create/schemas/v1.ts @@ -11,60 +11,172 @@ import { notifyWhenSchemaV1, alertDelaySchemaV1 } from '../../../response'; import { alertsFilterQuerySchemaV1 } from '../../../../alerts_filter_query'; export const actionFrequencySchema = schema.object({ - summary: schema.boolean(), + summary: schema.boolean({ + meta: { description: 'Indicates whether the action is a summary.' }, + }), notify_when: notifyWhenSchemaV1, - throttle: schema.nullable(schema.string({ validate: validateDurationV1 })), -}); - -export const actionAlertsFilterSchema = schema.object({ - query: schema.maybe(alertsFilterQuerySchemaV1), - timeframe: schema.maybe( - schema.object({ - days: schema.arrayOf( - schema.oneOf([ - schema.literal(1), - schema.literal(2), - schema.literal(3), - schema.literal(4), - schema.literal(5), - schema.literal(6), - schema.literal(7), - ]) - ), - hours: schema.object({ - start: schema.string({ - validate: validateHoursV1, - }), - end: schema.string({ - validate: validateHoursV1, - }), - }), - timezone: schema.string({ validate: validateTimezoneV1 }), + throttle: schema.nullable( + schema.string({ + validate: validateDurationV1, + meta: { + description: + 'The throttle interval, which defines how often an alert generates repeated actions. It is specified in seconds, minutes, hours, or days and is applicable only if `notify_when` is set to `onThrottleInterval`. NOTE: You cannot specify the throttle interval at both the rule and action level. The recommended method is to set it for each action. If you set it at the rule level then update the rule in Kibana, it is automatically changed to use action-specific values.', + }, }) ), }); -export const actionSchema = schema.object({ - group: schema.maybe(schema.string()), - id: schema.string(), - params: schema.recordOf(schema.string(), schema.maybe(schema.any()), { defaultValue: {} }), - frequency: schema.maybe(actionFrequencySchema), - uuid: schema.maybe(schema.string()), - alerts_filter: schema.maybe(actionAlertsFilterSchema), - use_alert_data_for_template: schema.maybe(schema.boolean()), -}); +export const actionAlertsFilterSchema = schema.object( + { + query: schema.maybe(alertsFilterQuerySchemaV1), + timeframe: schema.maybe( + schema.object( + { + days: schema.arrayOf( + schema.oneOf([ + schema.literal(1), + schema.literal(2), + schema.literal(3), + schema.literal(4), + schema.literal(5), + schema.literal(6), + schema.literal(7), + ]), + { + meta: { + description: + 'Defines the days of the week that the action can run, represented as an array of numbers. For example, `1` represents Monday. An empty array is equivalent to specifying all the days of the week.', + }, + } + ), + hours: schema.object( + { + start: schema.string({ + validate: validateHoursV1, + meta: { description: 'The start of the time frame in 24-hour notation (`hh:mm`).' }, + }), + end: schema.string({ + validate: validateHoursV1, + meta: { description: 'The end of the time frame in 24-hour notation (`hh:mm`).' }, + }), + }, + { + meta: { + description: + 'Defines the range of time in a day that the action can run. If the `start` value is `00:00` and the `end` value is `24:00`, actions be generated all day.', + }, + } + ), + timezone: schema.string({ + validate: validateTimezoneV1, + meta: { + description: + 'The ISO time zone for the `hours` values. Values such as `UTC` and `UTC+1` also work but lack built-in daylight savings time support and are not recommended.', + }, + }), + }, + { meta: { description: 'Defines a period that limits whether the action runs.' } } + ) + ), + }, + { + meta: { + description: + 'Conditions that affect whether the action runs. If you specify multiple conditions, all conditions must be met for the action to run. For example, if an alert occurs within the specified time frame and matches the query, the action runs.', + }, + } +); + +export const actionSchema = schema.object( + { + group: schema.maybe( + schema.string({ + meta: { + description: + "The group name, which affects when the action runs (for example, when the threshold is met or when the alert is recovered). Each rule type has a list of valid action group names. If you don't need to group actions, set to `default`.", + }, + }) + ), + id: schema.string({ + meta: { description: 'The identifier for the connector saved object.' }, + }), + params: schema.recordOf(schema.string(), schema.maybe(schema.any()), { + defaultValue: {}, + meta: { + description: + 'The parameters for the action, which are sent to the connector. The `params` are handled as Mustache templates and passed a default set of context.', + }, + }), + frequency: schema.maybe(actionFrequencySchema), + uuid: schema.maybe( + schema.string({ + meta: { description: 'A universally unique identifier (UUID) for the action.' }, + }) + ), + alerts_filter: schema.maybe(actionAlertsFilterSchema), + use_alert_data_for_template: schema.maybe(schema.boolean()), + }, + { + meta: { description: 'An action that runs under defined conditions.' }, + } +); export const createBodySchema = schema.object({ - name: schema.string(), - rule_type_id: schema.string(), - enabled: schema.boolean({ defaultValue: true }), - consumer: schema.string(), - tags: schema.arrayOf(schema.string(), { defaultValue: [] }), - throttle: schema.maybe(schema.nullable(schema.string({ validate: validateDurationV1 }))), - params: schema.recordOf(schema.string(), schema.maybe(schema.any()), { defaultValue: {} }), - schedule: schema.object({ - interval: schema.string({ validate: validateDurationV1 }), + name: schema.string({ + meta: { + description: + 'The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.', + }, + }), + rule_type_id: schema.string({ + meta: { description: 'The rule type identifier.' }, }), + enabled: schema.boolean({ + defaultValue: true, + meta: { + description: + 'Indicates whether you want to run the rule on an interval basis after it is created.', + }, + }), + consumer: schema.string({ + meta: { + description: + 'The name of the application or feature that owns the rule. For example: `alerts`, `apm`, `discover`, `infrastructure`, `logs`, `metrics`, `ml`, `monitoring`, `securitySolution`, `siem`, `stackAlerts`, or `uptime`.', + }, + }), + tags: schema.arrayOf(schema.string(), { + defaultValue: [], + meta: { description: 'The tags for the rule.' }, + }), + throttle: schema.maybe( + schema.nullable( + schema.string({ + validate: validateDurationV1, + meta: { + description: + 'Use the `throttle` property in the action `frequency` object instead. The throttle interval, which defines how often an alert generates repeated actions. NOTE: You cannot specify the throttle interval at both the rule and action level. If you set it at the rule level then update the rule in Kibana, it is automatically changed to use action-specific values.', + }, + }) + ) + ), + params: schema.recordOf(schema.string(), schema.maybe(schema.any()), { + defaultValue: {}, + meta: { description: 'The parameters for the rule.' }, + }), + schedule: schema.object( + { + interval: schema.string({ + validate: validateDurationV1, + meta: { description: 'The interval is specified in seconds, minutes, hours, or days.' }, + }), + }, + { + meta: { + description: + 'The check interval, which specifies how frequently the rule conditions are checked.', + }, + } + ), actions: schema.arrayOf(actionSchema, { defaultValue: [] }), notify_when: schema.maybe(schema.nullable(notifyWhenSchemaV1)), alert_delay: schema.maybe(alertDelaySchemaV1), diff --git a/x-pack/plugins/alerting/common/routes/rule/response/schemas/v1.ts b/x-pack/plugins/alerting/common/routes/rule/response/schemas/v1.ts index 2b6f09ef0dfd8..e78c9b88b5d64 100644 --- a/x-pack/plugins/alerting/common/routes/rule/response/schemas/v1.ts +++ b/x-pack/plugins/alerting/common/routes/rule/response/schemas/v1.ts @@ -27,7 +27,13 @@ export const notifyWhenSchema = schema.oneOf( schema.literal(ruleNotifyWhenV1.ACTIVE), schema.literal(ruleNotifyWhenV1.THROTTLE), ], - { validate: validateNotifyWhenV1 } + { + validate: validateNotifyWhenV1, + meta: { + description: + 'Indicates how often alerts generate actions. Valid values include: `onActionGroupChange`: Actions run when the alert status changes; `onActiveAlert`: Actions run when the alert becomes active and at each check interval while the rule conditions are met; `onThrottleInterval`: Actions run when the alert becomes active and at the interval specified in the throttle property while the rule conditions are met. NOTE: You cannot specify `notify_when` at both the rule and action level. The recommended method is to set it for each action. If you set it at the rule level then update the rule in Kibana, it is automatically changed to use action-specific values.', + }, + } ); const intervalScheduleSchema = schema.object({ @@ -183,9 +189,19 @@ export const ruleSnoozeScheduleSchema = schema.object({ skipRecurrences: schema.maybe(schema.arrayOf(schema.string())), }); -export const alertDelaySchema = schema.object({ - active: schema.number(), -}); +export const alertDelaySchema = schema.object( + { + active: schema.number({ + meta: { description: 'The number of consecutive runs that must meet the rule conditions.' }, + }), + }, + { + meta: { + description: + 'Indicates that an alert occurs only when the specified number of consecutive runs met the rule conditions.', + }, + } +); export const ruleResponseSchema = schema.object({ id: schema.string(), diff --git a/x-pack/plugins/alerting/server/integration_tests/__snapshots__/serverless_upgrade_and_rollback_checks.test.ts.snap b/x-pack/plugins/alerting/server/integration_tests/__snapshots__/serverless_upgrade_and_rollback_checks.test.ts.snap index 518c2b406db74..c0827083779f3 100644 --- a/x-pack/plugins/alerting/server/integration_tests/__snapshots__/serverless_upgrade_and_rollback_checks.test.ts.snap +++ b/x-pack/plugins/alerting/server/integration_tests/__snapshots__/serverless_upgrade_and_rollback_checks.test.ts.snap @@ -6097,7 +6097,7 @@ Object { Object { "additionalProperties": false, "properties": Object { - "is_customized": Object { + "isCustomized": Object { "type": "boolean", }, "type": Object { @@ -6107,7 +6107,7 @@ Object { }, "required": Array [ "type", - "is_customized", + "isCustomized", ], "type": "object", }, @@ -6596,7 +6596,7 @@ Object { Object { "additionalProperties": false, "properties": Object { - "is_customized": Object { + "isCustomized": Object { "type": "boolean", }, "type": Object { @@ -6606,7 +6606,7 @@ Object { }, "required": Array [ "type", - "is_customized", + "isCustomized", ], "type": "object", }, @@ -7158,7 +7158,7 @@ Object { Object { "additionalProperties": false, "properties": Object { - "is_customized": Object { + "isCustomized": Object { "type": "boolean", }, "type": Object { @@ -7168,7 +7168,7 @@ Object { }, "required": Array [ "type", - "is_customized", + "isCustomized", ], "type": "object", }, @@ -7592,7 +7592,7 @@ Object { Object { "additionalProperties": false, "properties": Object { - "is_customized": Object { + "isCustomized": Object { "type": "boolean", }, "type": Object { @@ -7602,7 +7602,7 @@ Object { }, "required": Array [ "type", - "is_customized", + "isCustomized", ], "type": "object", }, @@ -8132,7 +8132,7 @@ Object { Object { "additionalProperties": false, "properties": Object { - "is_customized": Object { + "isCustomized": Object { "type": "boolean", }, "type": Object { @@ -8142,7 +8142,7 @@ Object { }, "required": Array [ "type", - "is_customized", + "isCustomized", ], "type": "object", }, @@ -8844,7 +8844,7 @@ Object { Object { "additionalProperties": false, "properties": Object { - "is_customized": Object { + "isCustomized": Object { "type": "boolean", }, "type": Object { @@ -8854,7 +8854,7 @@ Object { }, "required": Array [ "type", - "is_customized", + "isCustomized", ], "type": "object", }, @@ -9556,7 +9556,7 @@ Object { Object { "additionalProperties": false, "properties": Object { - "is_customized": Object { + "isCustomized": Object { "type": "boolean", }, "type": Object { @@ -9566,7 +9566,7 @@ Object { }, "required": Array [ "type", - "is_customized", + "isCustomized", ], "type": "object", }, diff --git a/x-pack/plugins/alerting/server/lib/get_alerts_for_notification.test.ts b/x-pack/plugins/alerting/server/lib/get_alerts_for_notification.test.ts index 2528a27f19f9e..b50025b415178 100644 --- a/x-pack/plugins/alerting/server/lib/get_alerts_for_notification.test.ts +++ b/x-pack/plugins/alerting/server/lib/get_alerts_for_notification.test.ts @@ -674,6 +674,36 @@ describe('getAlertsForNotification', () => { expect(delayedAlertsCount).toBe(2); }); + test('should remove the alert from recoveredAlerts and should not return the alert in currentRecoveredAlerts if the activeCount is less than the rule alertDelay', () => { + const alert1 = new Alert('1', { + meta: { activeCount: 1, uuid: 'uuid-1' }, + }); + const alert2 = new Alert('2', { meta: { uuid: 'uuid-2' } }); + + const { recoveredAlerts, currentRecoveredAlerts, delayedAlertsCount } = + getAlertsForNotification( + DEFAULT_FLAPPING_SETTINGS, + true, + 'default', + 5, + {}, + {}, + { + // recovered alerts + '1': alert1, + '2': alert2, + }, + { + // current recovered alerts + '1': alert1, + '2': alert2, + } + ); + expect(recoveredAlerts).toMatchInlineSnapshot(`Object {}`); + expect(currentRecoveredAlerts).toMatchInlineSnapshot(`Object {}`); + expect(delayedAlertsCount).toBe(0); + }); + test('should update active alert to look like a new alert if the activeCount is equal to the rule alertDelay', () => { const alert2 = new Alert('2', { meta: { uuid: 'uuid-2' } }); diff --git a/x-pack/plugins/alerting/server/lib/get_alerts_for_notification.ts b/x-pack/plugins/alerting/server/lib/get_alerts_for_notification.ts index c5c7ac017b2c1..c1974810b46d0 100644 --- a/x-pack/plugins/alerting/server/lib/get_alerts_for_notification.ts +++ b/x-pack/plugins/alerting/server/lib/get_alerts_for_notification.ts @@ -54,6 +54,12 @@ export function getAlertsForNotification< for (const id of keys(currentRecoveredAlerts)) { const alert = recoveredAlerts[id]; + // if alert has not reached the alertDelay threshold don't recover the alert + if (alert.getActiveCount() < alertDelay) { + // remove from recovered alerts + delete recoveredAlerts[id]; + delete currentRecoveredAlerts[id]; + } alert.resetActiveCount(); if (flappingSettings.enabled) { const flapping = alert.getFlapping(); diff --git a/x-pack/plugins/alerting/server/routes/disable_rule.ts b/x-pack/plugins/alerting/server/routes/disable_rule.ts index 726b080bedbf1..6be1254fb9342 100644 --- a/x-pack/plugins/alerting/server/routes/disable_rule.ts +++ b/x-pack/plugins/alerting/server/routes/disable_rule.ts @@ -30,6 +30,10 @@ export const disableRuleRoute = ( router.post( { path: `${BASE_ALERTING_API_PATH}/rule/{id}/_disable`, + options: { + access: 'public', + description: `Disable a rule`, + }, validate: { params: paramSchema, body: bodySchema, diff --git a/x-pack/plugins/alerting/server/routes/enable_rule.ts b/x-pack/plugins/alerting/server/routes/enable_rule.ts index 84a4086cd245c..76c96fecaef5a 100644 --- a/x-pack/plugins/alerting/server/routes/enable_rule.ts +++ b/x-pack/plugins/alerting/server/routes/enable_rule.ts @@ -22,6 +22,10 @@ export const enableRuleRoute = ( router.post( { path: `${BASE_ALERTING_API_PATH}/rule/{id}/_enable`, + options: { + access: 'public', + description: `Enable a rule`, + }, validate: { params: paramSchema, }, diff --git a/x-pack/plugins/alerting/server/routes/health.ts b/x-pack/plugins/alerting/server/routes/health.ts index 7049abb0d9d13..5272876773b69 100644 --- a/x-pack/plugins/alerting/server/routes/health.ts +++ b/x-pack/plugins/alerting/server/routes/health.ts @@ -40,6 +40,10 @@ export const healthRoute = ( router.get( { path: `${BASE_ALERTING_API_PATH}/_health`, + options: { + access: 'public', + description: `Get the health of the alerting framework`, + }, validate: false, }, router.handleLegacyErrors( diff --git a/x-pack/plugins/alerting/server/routes/mute_all_rule.ts b/x-pack/plugins/alerting/server/routes/mute_all_rule.ts index 41b561db0b2fd..ca1f31bae3cb2 100644 --- a/x-pack/plugins/alerting/server/routes/mute_all_rule.ts +++ b/x-pack/plugins/alerting/server/routes/mute_all_rule.ts @@ -25,6 +25,10 @@ export const muteAllRuleRoute = ( router.post( { path: `${BASE_ALERTING_API_PATH}/rule/{id}/_mute_all`, + options: { + access: 'public', + description: `Mute all alerts`, + }, validate: { params: paramSchema, }, diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.ts index a5a27485ceb70..7299da7e8dd39 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.ts @@ -32,6 +32,10 @@ export const createRuleRoute = ({ router, licenseState, usageCounter }: RouteOpt router.post( { path: `${BASE_ALERTING_API_PATH}/rule/{id?}`, + options: { + access: 'public', + description: `Create a rule`, + }, validate: { body: createBodySchemaV1, params: createParamsSchemaV1, diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/delete/delete_rule_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/delete/delete_rule_route.ts index bdd264ee21bf9..bb862e3a7e5c9 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/delete/delete_rule_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/delete/delete_rule_route.ts @@ -21,6 +21,10 @@ export const deleteRuleRoute = ( router.delete( { path: `${BASE_ALERTING_API_PATH}/rule/{id}`, + options: { + access: 'public', + description: `Delete a rule`, + }, validate: { params: deleteRuleRequestParamsSchemaV1, }, diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/find/find_rules_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/find/find_rules_route.ts index 6baf208e016a1..ac2aa49956b3a 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/find/find_rules_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/find/find_rules_route.ts @@ -41,6 +41,10 @@ const buildFindRulesRoute = ({ router.get( { path, + options: { + access: 'public', + description: `Get rules`, + }, validate: { query: findRulesRequestQuerySchemaV1, }, diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/get/get_rule_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/get/get_rule_route.ts index 7f1b3932e1730..2764163641a97 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/get/get_rule_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/get/get_rule_route.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { IRouter } from '@kbn/core/server'; +import { IRouter, RouteConfigOptions, RouteMethod } from '@kbn/core/server'; import { ILicenseState } from '../../../../lib'; import { verifyAccessAndContext } from '../../../lib'; import type { RuleParamsV1 } from '../../../../../common/routes/rule/response'; @@ -28,16 +28,19 @@ interface BuildGetRulesRouteParams { path: string; router: IRouter; excludeFromPublicApi?: boolean; + options?: RouteConfigOptions; } const buildGetRuleRoute = ({ licenseState, path, router, excludeFromPublicApi = false, + options, }: BuildGetRulesRouteParams) => { router.get( { path, + options, validate: { params: getRuleRequestParamsSchemaV1, }, @@ -73,6 +76,10 @@ export const getRuleRoute = ( licenseState, path: `${BASE_ALERTING_API_PATH}/rule/{id}`, router, + options: { + access: 'public', + description: `Get rule details`, + }, }); export const getInternalRuleRoute = ( diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/mute_alert/mute_alert.ts b/x-pack/plugins/alerting/server/routes/rule/apis/mute_alert/mute_alert.ts index 45a0a37f3164c..2e7747f53b1b4 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/mute_alert/mute_alert.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/mute_alert/mute_alert.ts @@ -21,6 +21,10 @@ export const muteAlertRoute = ( router.post( { path: `${BASE_ALERTING_API_PATH}/rule/{rule_id}/alert/{alert_id}/_mute`, + options: { + access: 'public', + description: `Mute an alert`, + }, validate: { params: muteAlertParamsSchemaV1, }, diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/update/update_rule_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/update/update_rule_route.ts index 20bf059f04b1c..0edaf62ea7ddd 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/update/update_rule_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/update/update_rule_route.ts @@ -31,6 +31,10 @@ export const updateRuleRoute = ( router.put( { path: `${BASE_ALERTING_API_PATH}/rule/{id}`, + options: { + access: 'public', + description: `Update a rule`, + }, validate: { body: updateBodySchemaV1, params: updateParamsSchemaV1, diff --git a/x-pack/plugins/alerting/server/routes/rule_types.ts b/x-pack/plugins/alerting/server/routes/rule_types.ts index 4521bdfd167a2..5c20fc6df7d5d 100644 --- a/x-pack/plugins/alerting/server/routes/rule_types.ts +++ b/x-pack/plugins/alerting/server/routes/rule_types.ts @@ -55,6 +55,10 @@ export const ruleTypesRoute = ( router.get( { path: `${BASE_ALERTING_API_PATH}/rule_types`, + options: { + access: 'public', + description: `Get rule types`, + }, validate: {}, }, router.handleLegacyErrors( diff --git a/x-pack/plugins/alerting/server/routes/unmute_alert.ts b/x-pack/plugins/alerting/server/routes/unmute_alert.ts index 1e4191745f621..089f63911a902 100644 --- a/x-pack/plugins/alerting/server/routes/unmute_alert.ts +++ b/x-pack/plugins/alerting/server/routes/unmute_alert.ts @@ -32,6 +32,10 @@ export const unmuteAlertRoute = ( router.post( { path: `${BASE_ALERTING_API_PATH}/rule/{rule_id}/alert/{alert_id}/_unmute`, + options: { + access: 'public', + description: `Unmute an alert`, + }, validate: { params: paramSchema, }, diff --git a/x-pack/plugins/alerting/server/routes/unmute_all_rule.ts b/x-pack/plugins/alerting/server/routes/unmute_all_rule.ts index 4e102f96cf381..247f6377e4ad1 100644 --- a/x-pack/plugins/alerting/server/routes/unmute_all_rule.ts +++ b/x-pack/plugins/alerting/server/routes/unmute_all_rule.ts @@ -22,6 +22,10 @@ export const unmuteAllRuleRoute = ( router.post( { path: `${BASE_ALERTING_API_PATH}/rule/{id}/_unmute_all`, + options: { + access: 'public', + description: `Unmute all alerts`, + }, validate: { params: paramSchema, }, diff --git a/x-pack/plugins/alerting/server/routes/update_rule_api_key.ts b/x-pack/plugins/alerting/server/routes/update_rule_api_key.ts index 6ba598fe621e0..2838e206c92d7 100644 --- a/x-pack/plugins/alerting/server/routes/update_rule_api_key.ts +++ b/x-pack/plugins/alerting/server/routes/update_rule_api_key.ts @@ -22,6 +22,10 @@ export const updateRuleApiKeyRoute = ( router.post( { path: `${BASE_ALERTING_API_PATH}/rule/{id}/_update_api_key`, + options: { + access: 'public', + description: `Update the API key for a rule`, + }, validate: { params: paramSchema, }, diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx index fd317d09ddfd9..d088988c243fe 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx +++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx @@ -15,8 +15,10 @@ import { ReactEmbeddableRenderer, } from '@kbn/embeddable-plugin/public'; import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; -import React, { FC, useMemo } from 'react'; +import React, { FC } from 'react'; import ReactDOM from 'react-dom'; +import { useSearchApi } from '@kbn/presentation-publishing'; +import { omit } from 'lodash'; import { pluginServices } from '../../../public/services'; import { CANVAS_EMBEDDABLE_CLASSNAME } from '../../../common/lib'; import { RendererStrings } from '../../../i18n'; @@ -54,20 +56,23 @@ const renderReactEmbeddable = ({ core: CoreStart; }) => { // wrap in functional component to allow usage of hooks - const RendererWrapper: FC<{ canvasApi: CanvasContainerApi }> = ({ canvasApi }) => { + const RendererWrapper: FC<{}> = () => { const getAppContext = useGetAppContext(core); - - useMemo(() => { - canvasApi.getAppContext = getAppContext; - }, [canvasApi, getAppContext]); + const searchApi = useSearchApi({ filters: input.filters }); return ( ({ + ...container, + getAppContext, + getSerializedStateForChild: () => ({ + rawState: omit(input, ['disableTriggers', 'filters']), + }), + ...searchApi, + })} key={`${type}_${uuid}`} - state={{ rawState: input }} onAnyStateChange={(newState) => { const newExpression = embeddableInputToExpression( newState.rawState as unknown as EmbeddableInput, @@ -87,7 +92,7 @@ const renderReactEmbeddable = ({ className={CANVAS_EMBEDDABLE_CLASSNAME} style={{ width: '100%', height: '100%', cursor: 'auto' }} > - + ); diff --git a/x-pack/plugins/canvas/public/components/hooks/use_canvas_api.tsx b/x-pack/plugins/canvas/public/components/hooks/use_canvas_api.tsx index 4eb6ccaacb5d9..3d1784bf65c82 100644 --- a/x-pack/plugins/canvas/public/components/hooks/use_canvas_api.tsx +++ b/x-pack/plugins/canvas/public/components/hooks/use_canvas_api.tsx @@ -9,7 +9,8 @@ import { useCallback, useMemo } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { BehaviorSubject } from 'rxjs'; -import { EmbeddableInput, ViewMode } from '@kbn/embeddable-plugin/common'; +import { EmbeddableInput } from '@kbn/embeddable-plugin/common'; +import { ViewMode } from '@kbn/presentation-publishing'; import { embeddableInputToExpression } from '../../../canvas_plugin_src/renderers/embeddable/embeddable_input_to_expression'; import { CanvasContainerApi } from '../../../types'; @@ -35,9 +36,9 @@ export const useCanvasApi: () => CanvasContainerApi = () => { [selectedPageId, dispatch] ); - const getCanvasApi = useCallback(() => { + const getCanvasApi = useCallback((): CanvasContainerApi => { return { - viewMode: new BehaviorSubject(ViewMode.EDIT), // always in edit mode + viewMode: new BehaviorSubject('edit'), // always in edit mode addNewPanel: async ({ panelType, initialState, @@ -47,7 +48,12 @@ export const useCanvasApi: () => CanvasContainerApi = () => { }) => { createNewEmbeddable(panelType, initialState); }, - } as CanvasContainerApi; + disableTriggers: true, + /** + * getSerializedStateForChild is left out here because we cannot access the state here. That method + * is injected in `x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx` + */ + } as unknown as CanvasContainerApi; }, [createNewEmbeddable]); return useMemo(() => getCanvasApi(), [getCanvasApi]); diff --git a/x-pack/plugins/canvas/types/embeddables.ts b/x-pack/plugins/canvas/types/embeddables.ts index 38aae5f33be7b..18d85d49b24c3 100644 --- a/x-pack/plugins/canvas/types/embeddables.ts +++ b/x-pack/plugins/canvas/types/embeddables.ts @@ -8,8 +8,13 @@ import type { TimeRange } from '@kbn/es-query'; import { Filter } from '@kbn/es-query'; import { EmbeddableInput as Input } from '@kbn/embeddable-plugin/common'; -import { HasAppContext, PublishesViewMode } from '@kbn/presentation-publishing'; -import { CanAddNewPanel } from '@kbn/presentation-containers'; +import { + HasAppContext, + HasDisableTriggers, + PublishesViewMode, + PublishesUnifiedSearch, +} from '@kbn/presentation-publishing'; +import { CanAddNewPanel, HasSerializedChildState } from '@kbn/presentation-containers'; export type EmbeddableInput = Input & { timeRange?: TimeRange; @@ -17,4 +22,8 @@ export type EmbeddableInput = Input & { savedObjectId?: string; }; -export type CanvasContainerApi = PublishesViewMode & CanAddNewPanel & Partial; +export type CanvasContainerApi = PublishesViewMode & + CanAddNewPanel & + HasDisableTriggers & + HasSerializedChildState & + Partial; diff --git a/x-pack/plugins/cloud_integrations/cloud_data_migration/kibana.jsonc b/x-pack/plugins/cloud_integrations/cloud_data_migration/kibana.jsonc index 99fd8b066ddd2..ea019ef61b15e 100644 --- a/x-pack/plugins/cloud_integrations/cloud_data_migration/kibana.jsonc +++ b/x-pack/plugins/cloud_integrations/cloud_data_migration/kibana.jsonc @@ -1,7 +1,7 @@ { "type": "plugin", "id": "@kbn/cloud-data-migration-plugin", - "owner": "@elastic/platform-onboarding", + "owner": "@elastic/kibana-management", "description": "Static migration page where self-managed users can see text/copy about migrating to Elastic Cloud", "plugin": { "id": "cloudDataMigration", diff --git a/x-pack/plugins/cloud_security_posture/public/common/api/use_data_view.ts b/x-pack/plugins/cloud_security_posture/public/common/api/use_data_view.ts new file mode 100644 index 0000000000000..6f75ed3dc3958 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/common/api/use_data_view.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useQuery } from '@tanstack/react-query'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { CspClientPluginStartDeps } from '../../types'; + +/** + * Hook to retrieve a Data View by it's Index Pattern title + */ +export const useDataView = (indexPattern: string) => { + const { + data: { dataViews }, + } = useKibana().services; + + return useQuery(['useDataView', indexPattern], async () => { + const [dataView] = await dataViews.find(indexPattern); + + if (!dataView) { + throw new Error(`Data view not found [${indexPattern}]`); + } + + return dataView; + }); +}; diff --git a/x-pack/plugins/cloud_security_posture/public/common/api/use_latest_findings_data_view.ts b/x-pack/plugins/cloud_security_posture/public/common/api/use_latest_findings_data_view.ts deleted file mode 100644 index 442330a888a50..0000000000000 --- a/x-pack/plugins/cloud_security_posture/public/common/api/use_latest_findings_data_view.ts +++ /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 { useQuery } from '@tanstack/react-query'; -import { useKibana } from '@kbn/kibana-react-plugin/public'; -import type { DataView } from '@kbn/data-plugin/common'; -import { i18n } from '@kbn/i18n'; -import { - LATEST_FINDINGS_INDEX_PATTERN, - LATEST_VULNERABILITIES_INDEX_PATTERN, -} from '../../../common/constants'; -import { CspClientPluginStartDeps } from '../../types'; - -/** - * TODO: Remove this static labels once https://github.com/elastic/kibana/issues/172615 is resolved - */ -const cloudSecurityFieldLabels: Record = { - 'result.evaluation': i18n.translate( - 'xpack.csp.findings.findingsTable.findingsTableColumn.resultColumnLabel', - { defaultMessage: 'Result' } - ), - 'resource.id': i18n.translate( - 'xpack.csp.findings.findingsTable.findingsTableColumn.resourceIdColumnLabel', - { defaultMessage: 'Resource ID' } - ), - 'resource.name': i18n.translate( - 'xpack.csp.findings.findingsTable.findingsTableColumn.resourceNameColumnLabel', - { defaultMessage: 'Resource Name' } - ), - 'resource.sub_type': i18n.translate( - 'xpack.csp.findings.findingsTable.findingsTableColumn.resourceTypeColumnLabel', - { defaultMessage: 'Resource Type' } - ), - 'rule.benchmark.rule_number': i18n.translate( - 'xpack.csp.findings.findingsTable.findingsTableColumn.ruleNumberColumnLabel', - { defaultMessage: 'Rule Number' } - ), - 'rule.name': i18n.translate( - 'xpack.csp.findings.findingsTable.findingsTableColumn.ruleNameColumnLabel', - { defaultMessage: 'Rule Name' } - ), - 'rule.section': i18n.translate( - 'xpack.csp.findings.findingsTable.findingsTableColumn.ruleSectionColumnLabel', - { defaultMessage: 'CIS Section' } - ), - '@timestamp': i18n.translate( - 'xpack.csp.findings.findingsTable.findingsTableColumn.lastCheckedColumnLabel', - { defaultMessage: 'Last Checked' } - ), - 'vulnerability.id': i18n.translate( - 'xpack.csp.findings.findingsTable.findingsTableColumn.vulnerabilityIdColumnLabel', - { defaultMessage: 'Vulnerability' } - ), - 'vulnerability.score.base': i18n.translate( - 'xpack.csp.findings.findingsTable.findingsTableColumn.vulnerabilityScoreColumnLabel', - { defaultMessage: 'CVSS' } - ), - 'vulnerability.severity': i18n.translate( - 'xpack.csp.findings.findingsTable.findingsTableColumn.vulnerabilitySeverityColumnLabel', - { defaultMessage: 'Severity' } - ), - 'package.name': i18n.translate( - 'xpack.csp.findings.findingsTable.findingsTableColumn.packageNameColumnLabel', - { defaultMessage: 'Package' } - ), - 'package.version': i18n.translate( - 'xpack.csp.findings.findingsTable.findingsTableColumn.packageVersionColumnLabel', - { defaultMessage: 'Version' } - ), - 'package.fixed_version': i18n.translate( - 'xpack.csp.findings.findingsTable.findingsTableColumn.packageFixedVersionColumnLabel', - { defaultMessage: 'Fix Version' } - ), -} as const; - -/** - * TODO: use perfected kibana data views - */ -export const useLatestFindingsDataView = (dataView: string) => { - const { - data: { dataViews }, - } = useKibana().services; - - const findDataView = async (): Promise => { - const [dataViewObj] = await dataViews.find(dataView); - if (!dataViewObj) { - throw new Error(`Data view not found [Name: {${dataView}}]`); - } - - /** - * TODO: Remove this update logic once https://github.com/elastic/kibana/issues/172615 is resolved - */ - if ( - dataView === LATEST_FINDINGS_INDEX_PATTERN || - dataView === LATEST_VULNERABILITIES_INDEX_PATTERN - ) { - let shouldUpdate = false; - Object.entries(cloudSecurityFieldLabels).forEach(([field, label]) => { - if ( - !dataViewObj.getFieldAttrs()[field]?.customLabel || - dataViewObj.getFieldAttrs()[field]?.customLabel === field - ) { - dataViewObj.setFieldCustomLabel(field, label); - shouldUpdate = true; - } - }); - if (shouldUpdate) { - await dataViews.updateSavedObject(dataViewObj); - } - } - - return dataViewObj; - }; - - return useQuery([`useDataView-${dataView}`], findDataView); -}; diff --git a/x-pack/plugins/cloud_security_posture/public/common/api/use_stats_api.ts b/x-pack/plugins/cloud_security_posture/public/common/api/use_stats_api.ts index db6883810d672..e973633210d9c 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/api/use_stats_api.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/api/use_stats_api.ts @@ -15,8 +15,8 @@ import { } from '../../../common/constants'; // TODO: consolidate both hooks into one hook with a dynamic key -export const getCspmStatsKey = ['csp_cspm_dashboard_stats']; -export const getKspmStatsKey = ['csp_kspm_dashboard_stats']; +export const CSPM_STATS_QUERY_KEY = ['csp_cspm_dashboard_stats']; +export const KSPM_STATS_QUERY_KEY = ['csp_kspm_dashboard_stats']; export const getStatsRoute = (policyTemplate: PosturePolicyTemplate) => { return STATS_ROUTE_PATH.replace('{policy_template}', policyTemplate); @@ -27,7 +27,7 @@ export const useCspmStatsApi = ( ) => { const { http } = useKibana().services; return useQuery( - getCspmStatsKey, + CSPM_STATS_QUERY_KEY, () => http.get(getStatsRoute(CSPM_POLICY_TEMPLATE), { version: '2' }), options @@ -39,7 +39,7 @@ export const useKspmStatsApi = ( ) => { const { http } = useKibana().services; return useQuery( - getKspmStatsKey, + KSPM_STATS_QUERY_KEY, () => http.get(getStatsRoute(KSPM_POLICY_TEMPLATE), { version: '2' }), options diff --git a/x-pack/plugins/cloud_security_posture/public/common/hooks/use_navigate_findings.test.ts b/x-pack/plugins/cloud_security_posture/public/common/hooks/use_navigate_findings.test.ts index e3d213118dd51..670664bf46ef7 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/hooks/use_navigate_findings.test.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/hooks/use_navigate_findings.test.ts @@ -33,8 +33,8 @@ jest.mock('./use_kibana', () => ({ }, }), })); -jest.mock('../api/use_latest_findings_data_view', () => ({ - useLatestFindingsDataView: jest.fn().mockReturnValue({ +jest.mock('../api/use_data_view', () => ({ + useDataView: jest.fn().mockReturnValue({ status: 'success', data: { id: 'data-view-id', diff --git a/x-pack/plugins/cloud_security_posture/public/common/hooks/use_navigate_findings.ts b/x-pack/plugins/cloud_security_posture/public/common/hooks/use_navigate_findings.ts index 4b98057fc10c4..08d52a0cfe93f 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/hooks/use_navigate_findings.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/hooks/use_navigate_findings.ts @@ -15,7 +15,7 @@ import { import { findingsNavigation } from '../navigation/constants'; import { encodeQuery } from '../navigation/query_utils'; import { useKibana } from './use_kibana'; -import { useLatestFindingsDataView } from '../api/use_latest_findings_data_view'; +import { useDataView } from '../api/use_data_view'; interface NegatedValue { value: string | number; @@ -77,12 +77,12 @@ const useNavigate = (pathname: string, dataViewId = SECURITY_DEFAULT_DATA_VIEW_I }; export const useNavigateFindings = () => { - const { data } = useLatestFindingsDataView(LATEST_FINDINGS_INDEX_PATTERN); + const { data } = useDataView(LATEST_FINDINGS_INDEX_PATTERN); return useNavigate(findingsNavigation.findings_default.path, data?.id); }; export const useNavigateFindingsByResource = () => { - const { data } = useLatestFindingsDataView(LATEST_FINDINGS_INDEX_PATTERN); + const { data } = useDataView(LATEST_FINDINGS_INDEX_PATTERN); return useNavigate(findingsNavigation.findings_by_resource.path, data?.id); }; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/summary_section.tsx b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/summary_section.tsx index bf9b08ff7f211..a32d706cd774f 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/summary_section.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/compliance_dashboard/dashboard_sections/summary_section.tsx @@ -160,7 +160,7 @@ export const SummarySection = ({ gutterSize="l" css={css` // height for compliance by cis section with max rows - height: 310px; + height: 350px; `} data-test-subj={DASHBOARD_SUMMARY_CONTAINER} > diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.test.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.test.tsx index 7b7bd42561204..c955cc847a6c9 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.test.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.test.tsx @@ -8,7 +8,7 @@ import React from 'react'; import Chance from 'chance'; import type { UseQueryResult } from '@tanstack/react-query'; import { of } from 'rxjs'; -import { useLatestFindingsDataView } from '../../common/api/use_latest_findings_data_view'; +import { useDataView } from '../../common/api/use_data_view'; import { Configurations } from './configurations'; import { TestProvider } from '../../test/test_provider'; import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; @@ -27,7 +27,7 @@ import { expectIdsInDoc } from '../../test/utils'; import { PACKAGE_NOT_INSTALLED_TEST_SUBJECT } from '../../components/cloud_posture_page'; import { useLicenseManagementLocatorApi } from '../../common/api/use_license_management_locator_api'; -jest.mock('../../common/api/use_latest_findings_data_view'); +jest.mock('../../common/api/use_data_view'); jest.mock('../../common/api/use_setup_status_api'); jest.mock('../../common/api/use_license_management_locator_api'); jest.mock('../../common/hooks/use_subscription_status'); @@ -197,7 +197,7 @@ describe('', () => { })); (source.fetch$ as jest.Mock).mockReturnValue(of({ rawResponse: { hits: { hits: [] } } })); - (useLatestFindingsDataView as jest.Mock).mockReturnValue({ + (useDataView as jest.Mock).mockReturnValue({ status: 'success', data: createStubDataView({ spec: { diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.tsx index 60de443228281..1452bc60c3bf2 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.tsx @@ -12,14 +12,14 @@ import { LATEST_FINDINGS_INDEX_PATTERN } from '../../../common/constants'; import { useCspSetupStatusApi } from '../../common/api/use_setup_status_api'; import { NoFindingsStates } from '../../components/no_findings_states'; import { CloudPosturePage } from '../../components/cloud_posture_page'; -import { useLatestFindingsDataView } from '../../common/api/use_latest_findings_data_view'; +import { useDataView } from '../../common/api/use_data_view'; import { cloudPosturePages, findingsNavigation } from '../../common/navigation/constants'; import { LatestFindingsContainer } from './latest_findings/latest_findings_container'; import { DataViewContext } from '../../common/contexts/data_view_context'; export const Configurations = () => { const location = useLocation(); - const dataViewQuery = useLatestFindingsDataView(LATEST_FINDINGS_INDEX_PATTERN); + const dataViewQuery = useDataView(LATEST_FINDINGS_INDEX_PATTERN); const { data: getSetupStatus } = useCspSetupStatusApi(); const hasConfigurationFindings = getSetupStatus?.kspm.status === 'indexed' || getSetupStatus?.cspm.status === 'indexed'; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/overview_tab.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/overview_tab.tsx index 42808c02f5050..15fbbe608ec81 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/overview_tab.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/overview_tab.tsx @@ -28,7 +28,7 @@ import { LATEST_FINDINGS_INDEX_DEFAULT_NS, LATEST_FINDINGS_INDEX_PATTERN, } from '../../../../common/constants'; -import { useLatestFindingsDataView } from '../../../common/api/use_latest_findings_data_view'; +import { useDataView } from '../../../common/api/use_data_view'; import { useKibana } from '../../../common/hooks/use_kibana'; import { CspFinding } from '../../../../common/schemas/csp_finding'; import { CisKubernetesIcons, CodeBlock, CspFlyoutMarkdown } from './findings_flyout'; @@ -178,7 +178,7 @@ export const OverviewTab = ({ ruleFlyoutLink: string; }) => { const { discover } = useKibana().services; - const latestFindingsDataView = useLatestFindingsDataView(LATEST_FINDINGS_INDEX_PATTERN); + const latestFindingsDataView = useDataView(LATEST_FINDINGS_INDEX_PATTERN); const discoverIndexLink = useMemo( () => diff --git a/x-pack/plugins/cloud_security_posture/public/pages/rules/change_csp_rule_state.ts b/x-pack/plugins/cloud_security_posture/public/pages/rules/change_csp_rule_state.ts deleted file mode 100644 index a574ec5f3efee..0000000000000 --- a/x-pack/plugins/cloud_security_posture/public/pages/rules/change_csp_rule_state.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { useKibana } from '@kbn/kibana-react-plugin/public'; -import { useQueryClient } from '@tanstack/react-query'; -import { getRuleStatesKey } from '../configurations/latest_findings/use_get_benchmark_rules_state_api'; -import { getCspmStatsKey, getKspmStatsKey } from '../../common/api'; -import { BENCHMARK_INTEGRATION_QUERY_KEY_V2 } from '../benchmarks/use_csp_benchmark_integrations'; -import { - CspBenchmarkRulesBulkActionRequestSchema, - RuleStateAttributes, -} from '../../../common/types/latest'; -import { CSP_BENCHMARK_RULES_BULK_ACTION_ROUTE_PATH } from '../../../common/constants'; - -export type RuleStateAttributesWithoutStates = Omit; -export const useChangeCspRuleState = () => { - const { http } = useKibana().services; - const queryClient = useQueryClient(); - - return async (actionOnRule: 'mute' | 'unmute', ruleIds: RuleStateAttributesWithoutStates[]) => { - const query = { - action: actionOnRule, - rules: ruleIds, - }; - - const cspRuleBulkActionResponse = await http?.post( - CSP_BENCHMARK_RULES_BULK_ACTION_ROUTE_PATH, - { - version: '1', - body: JSON.stringify(query), - } - ); - await queryClient.invalidateQueries(BENCHMARK_INTEGRATION_QUERY_KEY_V2); // causing rules counters refetch - await queryClient.invalidateQueries(getCspmStatsKey); // causing cloud dashboard refetch - await queryClient.invalidateQueries(getKspmStatsKey); // causing kubernetes dashboard refetch - await queryClient.invalidateQueries(getRuleStatesKey); // the rule states are part of the findings query key, invalidating them will cause the latest findings to refetch only after the rules states were changed - - return cspRuleBulkActionResponse; - }; -}; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_container.tsx b/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_container.tsx index d50a351a0f1b6..c134e405f8a3c 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_container.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_container.tsx @@ -245,7 +245,6 @@ export const RulesContainer = () => { pageSize={rulesPageData.rules_page.length} isSearching={status === 'loading'} selectedRules={selectedRules} - refetchRulesStates={rulesStates.refetch} setEnabledDisabledItemsFilter={setEnabledDisabledItemsFilter} enabledDisabledItemsFilterState={enabledDisabledItemsFilter} setSelectAllRules={setSelectAllRules} @@ -268,16 +267,11 @@ export const RulesContainer = () => { }} selectedRuleId={params.ruleId} onRuleClick={navToRuleFlyout} - refetchRulesStates={rulesStates.refetch} selectedRules={selectedRules} setSelectedRules={setSelectedRules} /> {params.ruleId && rulesFlyoutData.metadata && ( - + )} ); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_flyout.tsx b/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_flyout.tsx index 7168b1f3efc20..3777646917e4a 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_flyout.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_flyout.tsx @@ -29,7 +29,7 @@ import { CspBenchmarkRuleMetadata } from '../../../common/types/latest'; import { getRuleList } from '../configurations/findings_flyout/rule_tab'; import { getRemediationList } from '../configurations/findings_flyout/overview_tab'; import * as TEST_SUBJECTS from './test_subjects'; -import { useChangeCspRuleState } from './change_csp_rule_state'; +import { useChangeCspRuleState } from './use_change_csp_rule_state'; import { CspBenchmarkRulesWithStates } from './rules_container'; import { showChangeBenchmarkRuleStatesSuccessToast, @@ -43,7 +43,6 @@ export const RULES_FLYOUT_SWITCH_BUTTON = 'rule-flyout-switch-button'; interface RuleFlyoutProps { onClose(): void; rule: CspBenchmarkRulesWithStates; - refetchRulesStates: () => void; } const tabs = [ @@ -65,9 +64,9 @@ const tabs = [ type RuleTab = typeof tabs[number]['id']; -export const RuleFlyout = ({ onClose, rule, refetchRulesStates }: RuleFlyoutProps) => { +export const RuleFlyout = ({ onClose, rule }: RuleFlyoutProps) => { const [tab, setTab] = useState('overview'); - const postRequestChangeRulesStates = useChangeCspRuleState(); + const { mutate: mutateRuleState } = useChangeCspRuleState(); const { data: rulesData } = useFetchDetectionRulesByTags( getFindingsDetectionRuleSearchTags(rule.metadata) ); @@ -84,8 +83,10 @@ export const RuleFlyout = ({ onClose, rule, refetchRulesStates }: RuleFlyoutProp rule_id: rule.metadata.id, }; const nextRuleStates = isRuleMuted ? 'unmute' : 'mute'; - await postRequestChangeRulesStates(nextRuleStates, [rulesObjectRequest]); - refetchRulesStates(); + await mutateRuleState({ + newState: nextRuleStates, + ruleIds: [rulesObjectRequest], + }); showChangeBenchmarkRuleStatesSuccessToast(startServices, isRuleMuted, { numberOfRules: 1, numberOfDetectionRules: rulesData?.total || 0, diff --git a/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_table.tsx b/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_table.tsx index a9e4b0501cfdf..05bed9ce85cd3 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_table.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_table.tsx @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useEffect, useMemo, useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { Criteria, EuiButtonEmpty, @@ -27,7 +27,7 @@ import { getFindingsDetectionRuleSearchTags } from '../../../common/utils/detect import { ColumnNameWithTooltip } from '../../components/column_name_with_tooltip'; import type { CspBenchmarkRulesWithStates, RulesState } from './rules_container'; import * as TEST_SUBJECTS from './test_subjects'; -import { RuleStateAttributesWithoutStates, useChangeCspRuleState } from './change_csp_rule_state'; +import { RuleStateUpdateRequest, useChangeCspRuleState } from './use_change_csp_rule_state'; import { showChangeBenchmarkRuleStatesSuccessToast } from '../../components/take_action'; import { fetchDetectionRulesByTags } from '../../common/api/use_fetch_detection_rules_by_tags'; @@ -41,7 +41,6 @@ type RulesTableProps = Pick< setPagination(pagination: Pick): void; onRuleClick: (ruleID: string) => void; selectedRuleId?: string; - refetchRulesStates: () => void; selectedRules: CspBenchmarkRulesWithStates[]; setSelectedRules: (rules: CspBenchmarkRulesWithStates[]) => void; onSortChange: (value: 'asc' | 'desc') => void; @@ -49,12 +48,9 @@ type RulesTableProps = Pick< type GetColumnProps = Pick< RulesTableProps, - 'onRuleClick' | 'refetchRulesStates' | 'selectedRules' | 'setSelectedRules' + 'onRuleClick' | 'selectedRules' | 'setSelectedRules' > & { - postRequestChangeRulesStates: ( - actionOnRule: 'mute' | 'unmute', - ruleIds: RuleStateAttributesWithoutStates[] - ) => void; + mutateRulesStates: (ruleStateUpdateRequest: RuleStateUpdateRequest) => void; items: CspBenchmarkRulesWithStates[]; setIsAllRulesSelectedThisPage: (isAllRulesSelected: boolean) => void; isAllRulesSelectedThisPage: boolean; @@ -75,7 +71,6 @@ export const RulesTable = ({ loading, error, selectedRuleId, - refetchRulesStates, selectedRules, setSelectedRules, onRuleClick, @@ -116,7 +111,7 @@ export const RulesTable = ({ const [isAllRulesSelectedThisPage, setIsAllRulesSelectedThisPage] = useState(false); - const postRequestChangeRulesStates = useChangeCspRuleState(); + const { mutate: mutateRulesStates } = useChangeCspRuleState(); const isCurrentPageRulesASubset = ( currentPageRulesArray: CspBenchmarkRulesWithStates[], @@ -140,35 +135,19 @@ export const RulesTable = ({ else setIsAllRulesSelectedThisPage(false); }, [items.length, selectedRules.length]); - const columns = useMemo(() => { - const startServices = { notifications, analytics, i18n: i18nStart, theme }; - return getColumns({ - refetchRulesStates, - postRequestChangeRulesStates, - selectedRules, - setSelectedRules, - items, - setIsAllRulesSelectedThisPage, - isAllRulesSelectedThisPage, - isCurrentPageRulesASubset, - onRuleClick, - http, - startServices, - }); - }, [ - refetchRulesStates, - postRequestChangeRulesStates, + const startServices = { notifications, analytics, i18n: i18nStart, theme }; + const columns = getColumns({ + mutateRulesStates, selectedRules, setSelectedRules, items, + setIsAllRulesSelectedThisPage, isAllRulesSelectedThisPage, + isCurrentPageRulesASubset, onRuleClick, - notifications, http, - analytics, - i18nStart, - theme, - ]); + startServices, + }); return ( <> @@ -189,8 +168,7 @@ export const RulesTable = ({ }; const getColumns = ({ - refetchRulesStates, - postRequestChangeRulesStates, + mutateRulesStates, selectedRules, setSelectedRules, items, @@ -316,18 +294,22 @@ const getColumns = ({ const changeCspRuleStateFn = async () => { if (rule?.metadata.benchmark.rule_number) { // Calling this function this way to make sure it didn't get called on every single row render, its only being called when user click on the switch button - const detectionRuleCount = ( + const detectionRulesForSelectedRule = ( await fetchDetectionRulesByTags( getFindingsDetectionRuleSearchTags(rule.metadata), { match: 'all' }, http ) ).total; - postRequestChangeRulesStates(nextRuleState, [rulesObjectRequest]); - refetchRulesStates(); + + mutateRulesStates({ + newState: nextRuleState, + ruleIds: [rulesObjectRequest], + }); + showChangeBenchmarkRuleStatesSuccessToast(startServices, isRuleMuted, { numberOfRules: 1, - numberOfDetectionRules: detectionRuleCount || 0, + numberOfDetectionRules: detectionRulesForSelectedRule || 0, }); } }; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_table_header.tsx b/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_table_header.tsx index 58a4ad46986eb..5aa8aae1dc590 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_table_header.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/rules/rules_table_header.tsx @@ -26,7 +26,10 @@ import { css } from '@emotion/react'; import { euiThemeVars } from '@kbn/ui-theme'; import { useKibana } from '../../common/hooks/use_kibana'; import { getFindingsDetectionRuleSearchTagsFromArrayOfRules } from '../../../common/utils/detection_rules'; -import { RuleStateAttributesWithoutStates, useChangeCspRuleState } from './change_csp_rule_state'; +import { + RuleStateAttributesWithoutStates, + useChangeCspRuleState, +} from './use_change_csp_rule_state'; import { CspBenchmarkRulesWithStates } from './rules_container'; import { MultiSelectFilter } from '../../common/component/multi_select_filter'; import { showChangeBenchmarkRuleStatesSuccessToast } from '../../components/take_action'; @@ -53,7 +56,6 @@ interface RulesTableToolbarProps { isSearching: boolean; pageSize: number; selectedRules: CspBenchmarkRulesWithStates[]; - refetchRulesStates: () => void; setEnabledDisabledItemsFilter: (filterState: string) => void; enabledDisabledItemsFilterState: string; setSelectAllRules: () => void; @@ -64,7 +66,6 @@ interface RuleTableCount { pageSize: number; total: number; selectedRules: CspBenchmarkRulesWithStates[]; - refetchRulesStates: () => void; setSelectAllRules: () => void; setSelectedRules: (rules: CspBenchmarkRulesWithStates[]) => void; } @@ -80,7 +81,6 @@ export const RulesTableHeader = ({ sectionSelectOptions, ruleNumberSelectOptions, selectedRules, - refetchRulesStates, setEnabledDisabledItemsFilter, enabledDisabledItemsFilterState, setSelectAllRules, @@ -198,7 +198,6 @@ export const RulesTableHeader = ({ pageSize={pageSize} total={totalRulesCount} selectedRules={selectedRules} - refetchRulesStates={refetchRulesStates} setSelectAllRules={setSelectAllRules} setSelectedRules={setSelectedRules} /> @@ -240,7 +239,6 @@ const CurrentPageOfTotal = ({ pageSize, total, selectedRules, - refetchRulesStates, setSelectAllRules, setSelectedRules, }: RuleTableCount) => { @@ -249,7 +247,8 @@ const CurrentPageOfTotal = ({ setIsPopoverOpen((e) => !e); }; - const { data: rulesData } = useFetchDetectionRulesByTags( + const { mutate: mutateRulesStates } = useChangeCspRuleState(); + const { data: detectionRulesForSelectedRules } = useFetchDetectionRulesByTags( getFindingsDetectionRuleSearchTagsFromArrayOfRules(selectedRules.map((rule) => rule.metadata)), { match: 'any' } ); @@ -257,7 +256,6 @@ const CurrentPageOfTotal = ({ const { notifications, analytics, i18n: i18nStart, theme } = useKibana().services; const startServices = { notifications, analytics, i18n: i18nStart, theme }; - const postRequestChangeRulesState = useChangeCspRuleState(); const changeRulesState = async (state: 'mute' | 'unmute') => { const bulkSelectedRules: RuleStateAttributesWithoutStates[] = selectedRules.map( (e: CspBenchmarkRulesWithStates) => ({ @@ -269,12 +267,14 @@ const CurrentPageOfTotal = ({ ); // Only do the API Call IF there are no undefined value for rule number in the selected rules if (!bulkSelectedRules.some((rule) => rule.rule_number === undefined)) { - await postRequestChangeRulesState(state, bulkSelectedRules); - refetchRulesStates(); + mutateRulesStates({ + newState: state, + ruleIds: bulkSelectedRules, + }); setIsPopoverOpen(false); showChangeBenchmarkRuleStatesSuccessToast(startServices, state !== 'mute', { numberOfRules: bulkSelectedRules.length, - numberOfDetectionRules: rulesData?.total || 0, + numberOfDetectionRules: detectionRulesForSelectedRules?.total || 0, }); } }; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/rules/use_change_csp_rule_state.test.tsx b/x-pack/plugins/cloud_security_posture/public/pages/rules/use_change_csp_rule_state.test.tsx new file mode 100644 index 0000000000000..cd205bb7f6b7b --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/pages/rules/use_change_csp_rule_state.test.tsx @@ -0,0 +1,333 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { act, renderHook } from '@testing-library/react-hooks'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { + useChangeCspRuleState, + createRulesWithUpdatedState, + RuleStateUpdateRequest, +} from './use_change_csp_rule_state'; +import { CSP_RULES_STATES_QUERY_KEY } from './use_csp_rules_state'; +import { BENCHMARK_INTEGRATION_QUERY_KEY_V2 } from '../benchmarks/use_csp_benchmark_integrations'; +import { CSPM_STATS_QUERY_KEY, KSPM_STATS_QUERY_KEY } from '../../common/api'; +import { CSP_BENCHMARK_RULES_BULK_ACTION_ROUTE_PATH } from '../../../common/constants'; +import { RuleStateAttributes } from '../../../common/types/rules/v4'; + +const initialRules = { + rule_1: { + benchmark_id: 'benchmark_id', + benchmark_version: 'benchmark_version', + rule_number: '1', + rule_id: 'rule_1', + muted: false, + }, + rule_2: { + benchmark_id: 'benchmark_id', + benchmark_version: 'benchmark_version', + rule_number: '2', + rule_id: 'rule_2', + muted: false, + }, + rule_3: { + benchmark_id: 'benchmark_id', + benchmark_version: 'benchmark_version', + rule_number: '3', + rule_id: 'rule_3', + muted: false, + }, +}; + +jest.mock('@kbn/kibana-react-plugin/public', () => ({ + useKibana: jest.fn().mockReturnValue({ + services: { + http: { + post: jest.fn(), + }, + }, + }), +})); + +const testWrapper = () => { + const queryClient = new QueryClient({ + defaultOptions: { + queries: { + retry: false, + }, + }, + // this is needed to avoid the errors in the console that are cause by QueryClient` + logger: { + log: jest.fn(), + warn: jest.fn(), + error: () => {}, + }, + }); + + queryClient.setQueryData(CSP_RULES_STATES_QUERY_KEY, { ...initialRules }); + + return { + wrapper: ({ children }: { children: React.ReactNode | React.ReactNode[] }) => ( + {children} + ), + queryClient, + }; +}; + +describe('use_change_csp_rule_state', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should call http.post with the correct parameters', async () => { + const appMockRender = testWrapper(); + const httpPostSpy = jest.spyOn(useKibana().services.http!, 'post'); + + const { result, waitForNextUpdate } = await renderHook(() => useChangeCspRuleState(), { + wrapper: appMockRender.wrapper, + }); + + const mockRuleStateUpdateRequest: RuleStateUpdateRequest = { + newState: 'mute', + ruleIds: [ + { + benchmark_id: 'benchmark_id', + benchmark_version: 'benchmark_version', + rule_number: '1', + rule_id: 'rule_1', + }, + ], + }; + + act(() => { + result.current.mutate(mockRuleStateUpdateRequest); + }); + + await waitForNextUpdate(); + + expect(httpPostSpy).toHaveBeenCalledWith(CSP_BENCHMARK_RULES_BULK_ACTION_ROUTE_PATH, { + version: '1', + body: JSON.stringify({ + action: 'mute', + rules: [ + { + benchmark_id: 'benchmark_id', + benchmark_version: 'benchmark_version', + rule_number: '1', + rule_id: 'rule_1', + }, + ], + }), + }); + }); + + it('should cancel queries and update query data onMutate', async () => { + const appMockRender = testWrapper(); + const queryClientSpy = jest.spyOn(appMockRender.queryClient, 'cancelQueries'); + const queryClientGetSpy = jest.spyOn(appMockRender.queryClient, 'getQueryData'); + const mockSetQueryDataSpy = jest.spyOn(appMockRender.queryClient, 'setQueryData'); + + const { result, waitForNextUpdate } = await renderHook(() => useChangeCspRuleState(), { + wrapper: appMockRender.wrapper, + }); + + const mockRuleStateUpdateRequest: RuleStateUpdateRequest = { + newState: 'mute', + ruleIds: [ + { + benchmark_id: 'benchmark_id', + benchmark_version: 'benchmark_version', + rule_number: '1', + rule_id: 'rule_1', + }, + ], + }; + + act(() => { + result.current.mutate(mockRuleStateUpdateRequest); + }); + + await waitForNextUpdate(); + + const expectedMutatedRules = { + ...initialRules, + rule_1: { ...initialRules.rule_1, muted: true }, + }; + + expect(queryClientSpy).toHaveBeenCalled(); + expect(queryClientGetSpy).toHaveBeenCalled(); + expect(mockSetQueryDataSpy).toHaveBeenCalled(); + expect(mockSetQueryDataSpy).toHaveReturnedWith(expectedMutatedRules); + }); + + it('should invalidate queries onSettled', async () => { + const appMockRender = testWrapper(); + const mockInvalidateQueriesSpy = jest.spyOn(appMockRender.queryClient, 'invalidateQueries'); + + const { result, waitForNextUpdate } = await renderHook(() => useChangeCspRuleState(), { + wrapper: appMockRender.wrapper, + }); + + const mockRuleStateUpdateRequest: RuleStateUpdateRequest = { + newState: 'mute', + ruleIds: [ + { + benchmark_id: 'benchmark_id', + benchmark_version: 'benchmark_version', + rule_number: '1', + rule_id: 'rule_1', + }, + ], + }; + + act(() => { + result.current.mutate(mockRuleStateUpdateRequest); + }); + + await waitForNextUpdate(); + + expect(mockInvalidateQueriesSpy).toHaveBeenCalledWith(BENCHMARK_INTEGRATION_QUERY_KEY_V2); + expect(mockInvalidateQueriesSpy).toHaveBeenCalledWith(CSPM_STATS_QUERY_KEY); + expect(mockInvalidateQueriesSpy).toHaveBeenCalledWith(KSPM_STATS_QUERY_KEY); + expect(mockInvalidateQueriesSpy).toHaveBeenCalledWith(CSP_RULES_STATES_QUERY_KEY); + }); + + it('should restore previous query data onError', async () => { + const appMockRender = testWrapper(); + const mockSetQueryDataSpy = jest.spyOn(appMockRender.queryClient, 'setQueryData'); + + const { result, waitForNextUpdate } = await renderHook(() => useChangeCspRuleState(), { + wrapper: appMockRender.wrapper, + }); + + const mockRuleStateUpdateRequest: RuleStateUpdateRequest = { + newState: 'mute', + ruleIds: [ + { + benchmark_id: 'benchmark_id', + benchmark_version: 'benchmark_version', + rule_number: '1', + // forcing an error by providing a ruleId that does not exist in the cache + rule_id: 'shouldnotexist', + }, + ], + }; + + act(() => { + result.current.mutate(mockRuleStateUpdateRequest); + }); + + await waitForNextUpdate(); + + expect(mockSetQueryDataSpy).toHaveBeenCalled(); + expect(mockSetQueryDataSpy).toHaveReturnedWith(initialRules); + }); + + it('creates the new set of cache rules in a muted state when calling createRulesWithUpdatedState', async () => { + const request: RuleStateUpdateRequest = { + newState: 'mute', + ruleIds: [ + { + benchmark_id: 'benchmark_id', + benchmark_version: 'benchmark_version', + rule_number: '1', + rule_id: 'rule_1', + }, + { + benchmark_id: 'benchmark_id', + benchmark_version: 'benchmark_version', + rule_number: '2', + rule_id: 'rule_2', + }, + ], + }; + + const updateRules: Record = { + rule_1: { + benchmark_id: 'benchmark_id', + benchmark_version: 'benchmark_version', + rule_number: '1', + rule_id: 'rule_1', + muted: true, + }, + rule_2: { + benchmark_id: 'benchmark_id', + benchmark_version: 'benchmark_version', + rule_number: '2', + rule_id: 'rule_2', + muted: true, + }, + }; + + const newRulesState = createRulesWithUpdatedState(request, initialRules); + expect(newRulesState).toEqual({ ...initialRules, ...updateRules }); + }); + + it('creates the new cache with rules in a unmute state', async () => { + const initialMutedRules: Record = { + rule_1: { + benchmark_id: 'benchmark_id', + benchmark_version: 'benchmark_version', + rule_number: '1', + rule_id: 'rule_1', + muted: true, + }, + rule_2: { + benchmark_id: 'benchmark_id', + benchmark_version: 'benchmark_version', + rule_number: '2', + rule_id: 'rule_2', + muted: true, + }, + rule_3: { + benchmark_id: 'benchmark_id', + benchmark_version: 'benchmark_version', + rule_number: '3', + rule_id: 'rule_3', + muted: false, + }, + }; + + const request: RuleStateUpdateRequest = { + newState: 'unmute', + ruleIds: [ + { + benchmark_id: 'benchmark_id', + benchmark_version: 'benchmark_version', + rule_number: '1', + rule_id: 'rule_1', + }, + { + benchmark_id: 'benchmark_id', + benchmark_version: 'benchmark_version', + rule_number: '2', + rule_id: 'rule_2', + }, + ], + }; + + const updateRules: Record = { + rule_1: { + benchmark_id: 'benchmark_id', + benchmark_version: 'benchmark_version', + rule_number: '1', + rule_id: 'rule_1', + muted: false, + }, + rule_2: { + benchmark_id: 'benchmark_id', + benchmark_version: 'benchmark_version', + rule_number: '2', + rule_id: 'rule_2', + muted: false, + }, + }; + + const newRulesState = createRulesWithUpdatedState(request, initialMutedRules); + expect(newRulesState).toEqual({ ...initialMutedRules, ...updateRules }); + }); +}); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/rules/use_change_csp_rule_state.ts b/x-pack/plugins/cloud_security_posture/public/pages/rules/use_change_csp_rule_state.ts new file mode 100644 index 0000000000000..bbf175b107f6e --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/pages/rules/use_change_csp_rule_state.ts @@ -0,0 +1,100 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { useQueryClient, useMutation } from '@tanstack/react-query'; +import { CSP_RULES_STATES_QUERY_KEY } from './use_csp_rules_state'; +import { CSPM_STATS_QUERY_KEY, KSPM_STATS_QUERY_KEY } from '../../common/api'; +import { BENCHMARK_INTEGRATION_QUERY_KEY_V2 } from '../benchmarks/use_csp_benchmark_integrations'; +import { + CspBenchmarkRulesBulkActionRequestSchema, + RuleStateAttributes, +} from '../../../common/types/latest'; +import { CSP_BENCHMARK_RULES_BULK_ACTION_ROUTE_PATH } from '../../../common/constants'; + +export type RuleStateAttributesWithoutStates = Omit; +export interface RuleStateUpdateRequest { + newState: 'mute' | 'unmute'; + ruleIds: RuleStateAttributesWithoutStates[]; +} + +export const useChangeCspRuleState = () => { + const { http } = useKibana().services; + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: async (ruleStateUpdateRequest: RuleStateUpdateRequest) => { + await http?.post( + CSP_BENCHMARK_RULES_BULK_ACTION_ROUTE_PATH, + { + version: '1', + body: JSON.stringify({ + action: ruleStateUpdateRequest.newState, + rules: ruleStateUpdateRequest.ruleIds, + }), + } + ); + }, + onMutate: async (ruleStateUpdateRequest: RuleStateUpdateRequest) => { + // Cancel any outgoing refetches (so they don't overwrite our optimistic update) + await queryClient.cancelQueries(CSP_RULES_STATES_QUERY_KEY); + + // Snapshot the previous rules + const previousCspRules = queryClient.getQueryData(CSP_RULES_STATES_QUERY_KEY); + + // Optimistically update to the rules that have state changes + queryClient.setQueryData( + CSP_RULES_STATES_QUERY_KEY, + (currentRuleStates: Record | undefined) => { + if (!currentRuleStates) { + return currentRuleStates; + } + return createRulesWithUpdatedState(ruleStateUpdateRequest, currentRuleStates); + } + ); + + // Return a context object with the previous value + return { previousCspRules }; + }, + onSettled: () => { + queryClient.invalidateQueries(BENCHMARK_INTEGRATION_QUERY_KEY_V2); + queryClient.invalidateQueries(CSPM_STATS_QUERY_KEY); + queryClient.invalidateQueries(KSPM_STATS_QUERY_KEY); + queryClient.invalidateQueries(CSP_RULES_STATES_QUERY_KEY); + }, + onError: (err, variables, context) => { + if (context?.previousCspRules) { + queryClient.setQueryData(CSP_RULES_STATES_QUERY_KEY, context.previousCspRules); + } + }, + }); +}; + +export function createRulesWithUpdatedState( + ruleStateUpdateRequest: RuleStateUpdateRequest, + currentRuleStates: Record +) { + const updateRuleStates: Record = {}; + ruleStateUpdateRequest.ruleIds.forEach((ruleId) => { + const matchingRuleKey = Object.keys(currentRuleStates).find( + (key) => currentRuleStates[key].rule_id === ruleId.rule_id + ); + if (matchingRuleKey) { + const updatedRule = { + ...currentRuleStates[matchingRuleKey], + muted: ruleStateUpdateRequest.newState === 'mute', + }; + + updateRuleStates[matchingRuleKey] = updatedRule; + } + }); + + return { + ...currentRuleStates, + ...updateRuleStates, + }; +} diff --git a/x-pack/plugins/cloud_security_posture/public/pages/rules/use_csp_rules_state.ts b/x-pack/plugins/cloud_security_posture/public/pages/rules/use_csp_rules_state.ts index da34cf8b247c7..e712b130e1651 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/rules/use_csp_rules_state.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/rules/use_csp_rules_state.ts @@ -10,13 +10,13 @@ import { CspBenchmarkRulesStates } from '../../../common/types/latest'; import { CSP_GET_BENCHMARK_RULES_STATE_ROUTE_PATH } from '../../../common/constants'; import { useKibana } from '../../common/hooks/use_kibana'; -const QUERY_KEY_V1 = 'csp_rules_states_v1'; +export const CSP_RULES_STATES_QUERY_KEY = ['csp_rules_states_v1']; export const useCspGetRulesStates = () => { const { http } = useKibana().services; return useQuery( - [QUERY_KEY_V1], + CSP_RULES_STATES_QUERY_KEY, () => http.get(CSP_GET_BENCHMARK_RULES_STATE_ROUTE_PATH, { version: '1', diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities.tsx index aca54e19bfccf..7f48cf18fb044 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities.tsx @@ -11,12 +11,12 @@ import { NoVulnerabilitiesStates } from '../../components/no_vulnerabilities_sta import { useCspSetupStatusApi } from '../../common/api/use_setup_status_api'; import { CloudPosturePage } from '../../components/cloud_posture_page'; import { findingsNavigation } from '../../common/navigation/constants'; -import { useLatestFindingsDataView } from '../../common/api/use_latest_findings_data_view'; +import { useDataView } from '../../common/api/use_data_view'; import { LatestVulnerabilitiesContainer } from './latest_vulnerabilities_container'; import { DataViewContext } from '../../common/contexts/data_view_context'; export const Vulnerabilities = () => { - const dataViewQuery = useLatestFindingsDataView(LATEST_VULNERABILITIES_INDEX_PATTERN); + const dataViewQuery = useDataView(LATEST_VULNERABILITIES_INDEX_PATTERN); const getSetupStatus = useCspSetupStatusApi(); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilties.test.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilties.test.tsx index 24c12405c1436..3a1d83e4189fc 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilties.test.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilties.test.tsx @@ -13,7 +13,7 @@ import { VULN_MGMT_POLICY_TEMPLATE, } from '../../../common/constants'; import { useCspSetupStatusApi } from '../../common/api/use_setup_status_api'; -import { useLatestFindingsDataView } from '../../common/api/use_latest_findings_data_view'; +import { useDataView } from '../../common/api/use_data_view'; import { useSubscriptionStatus } from '../../common/hooks/use_subscription_status'; import { createReactQueryResponse } from '../../test/fixtures/react_query'; import { useCISIntegrationPoliciesLink } from '../../common/navigation/use_navigate_to_cis_integration_policies'; @@ -28,7 +28,7 @@ import { TestProvider } from '../../test/test_provider'; import { useLicenseManagementLocatorApi } from '../../common/api/use_license_management_locator_api'; import { createStubDataView } from '@kbn/data-views-plugin/common/stubs'; -jest.mock('../../common/api/use_latest_findings_data_view'); +jest.mock('../../common/api/use_data_view'); jest.mock('../../common/api/use_setup_status_api'); jest.mock('../../common/api/use_license_management_locator_api'); jest.mock('../../common/hooks/use_subscription_status'); @@ -54,7 +54,7 @@ beforeEach(() => { }) ); - (useLatestFindingsDataView as jest.Mock).mockReturnValue({ + (useDataView as jest.Mock).mockReturnValue({ status: 'success', data: createStubDataView({ spec: { diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_dashboard.test.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_dashboard.test.tsx index de41bfdccd9c1..9e68d5d051c6b 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_dashboard.test.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_dashboard.test.tsx @@ -32,7 +32,7 @@ import { VULNERABILITY_DASHBOARD_CONTAINER } from '../compliance_dashboard/test_ import { useVulnerabilityDashboardApi } from '../../common/api/use_vulnerability_dashboard_api'; import { mockCnvmDashboardData } from './_mocks_/vulnerability_dashboard.mock'; -jest.mock('../../common/api/use_latest_findings_data_view'); +jest.mock('../../common/api/use_data_view'); jest.mock('../../common/api/use_setup_status_api'); jest.mock('../../common/api/use_license_management_locator_api'); jest.mock('../../common/hooks/use_subscription_status'); diff --git a/x-pack/plugins/elastic_assistant/common/constants.ts b/x-pack/plugins/elastic_assistant/common/constants.ts index 77fd99c7d5eb6..5c5233eaaa6c8 100755 --- a/x-pack/plugins/elastic_assistant/common/constants.ts +++ b/x-pack/plugins/elastic_assistant/common/constants.ts @@ -15,9 +15,6 @@ export const POST_ACTIONS_CONNECTOR_EXECUTE = `${BASE_PATH}/actions/connector/{c // Attack discovery export const ATTACK_DISCOVERY = `${BASE_PATH}/attack_discovery`; -// Knowledge Base -export const KNOWLEDGE_BASE = `${BASE_PATH}/knowledge_base/{resource?}`; - // Model Evaluation export const EVALUATE = `${BASE_PATH}/evaluate`; diff --git a/x-pack/plugins/elastic_assistant/server/__mocks__/request.ts b/x-pack/plugins/elastic_assistant/server/__mocks__/request.ts index 671cb1b2f0a88..0850938633322 100644 --- a/x-pack/plugins/elastic_assistant/server/__mocks__/request.ts +++ b/x-pack/plugins/elastic_assistant/server/__mocks__/request.ts @@ -5,7 +5,7 @@ * 2.0. */ import { httpServerMock } from '@kbn/core/server/mocks'; -import { CAPABILITIES, EVALUATE, KNOWLEDGE_BASE } from '../../common/constants'; +import { CAPABILITIES, EVALUATE } from '../../common/constants'; import { ConversationCreateProps, ConversationUpdateProps, @@ -16,6 +16,7 @@ import { ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL_BY_ID, ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL_BY_ID_MESSAGES, ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL_FIND, + ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_URL, ELASTIC_AI_ASSISTANT_PROMPTS_URL_BULK_ACTION, ELASTIC_AI_ASSISTANT_PROMPTS_URL_FIND, PostEvaluateRequestBodyInput, @@ -42,21 +43,21 @@ export const requestMock = { export const getGetKnowledgeBaseStatusRequest = (resource?: string) => requestMock.create({ method: 'get', - path: KNOWLEDGE_BASE, + path: ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_URL, query: { resource }, }); export const getPostKnowledgeBaseRequest = (resource?: string) => requestMock.create({ method: 'post', - path: KNOWLEDGE_BASE, + path: ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_URL, query: { resource }, }); export const getDeleteKnowledgeBaseRequest = (resource?: string) => requestMock.create({ method: 'delete', - path: KNOWLEDGE_BASE, + path: ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_URL, query: { resource }, }); 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 78982d0437650..6c5d9b2bc4d57 100644 --- a/x-pack/plugins/elastic_assistant/server/__mocks__/request_context.ts +++ b/x-pack/plugins/elastic_assistant/server/__mocks__/request_context.ts @@ -17,6 +17,8 @@ import { PluginStartContract as ActionsPluginStart } from '@kbn/actions-plugin/s import { conversationsDataClientMock, dataClientMock } from './data_clients.mock'; import { AIAssistantConversationsDataClient } from '../ai_assistant_data_clients/conversations'; import { AIAssistantDataClient } from '../ai_assistant_data_clients'; +import { AIAssistantKnowledgeBaseDataClient } from '../ai_assistant_data_clients/knowledge_base'; +import { defaultAssistantFeatures } from '@kbn/elastic-assistant-common'; export const createMockClients = () => { const core = coreMock.createRequestHandlerContext(); @@ -27,11 +29,12 @@ export const createMockClients = () => { clusterClient: core.elasticsearch.client, elasticAssistant: { actions: actionsClientMock.create(), - getRegisteredFeatures: jest.fn(), + getRegisteredFeatures: jest.fn(() => defaultAssistantFeatures), getRegisteredTools: jest.fn(), logger: loggingSystemMock.createLogger(), telemetry: coreMock.createSetup().analytics, getAIAssistantConversationsDataClient: conversationsDataClientMock.create(), + getAIAssistantKnowledgeBaseDataClient: dataClientMock.create(), getAIAssistantPromptsDataClient: dataClientMock.create(), getAIAssistantAnonymizationFieldsDataClient: dataClientMock.create(), getSpaceId: jest.fn(), @@ -85,7 +88,7 @@ const createElasticAssistantRequestContextMock = ( ): jest.Mocked => { return { actions: clients.elasticAssistant.actions as unknown as ActionsPluginStart, - getRegisteredFeatures: jest.fn(), + getRegisteredFeatures: jest.fn((pluginName: string) => defaultAssistantFeatures), getRegisteredTools: jest.fn(), logger: clients.elasticAssistant.logger, @@ -106,6 +109,14 @@ const createElasticAssistantRequestContextMock = ( () => clients.elasticAssistant.getAIAssistantPromptsDataClient ) as unknown as jest.MockInstance, [], unknown> & (() => Promise), + getAIAssistantKnowledgeBaseDataClient: jest.fn( + () => clients.elasticAssistant.getAIAssistantKnowledgeBaseDataClient + ) as unknown as jest.MockInstance< + Promise, + [boolean], + unknown + > & + ((initializeKnowledgeBase: boolean) => Promise), getCurrentUser: jest.fn(), getServerBasePath: jest.fn(), getSpaceId: jest.fn(), diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/index.test.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/index.test.ts index 550d523db4c6f..38426dd06a36f 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/index.test.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/index.test.ts @@ -33,7 +33,7 @@ describe('AIAssistantConversationsDataClient', () => { logger, elasticsearchClientPromise: Promise.resolve(clusterClient), spaceId: 'default', - indexPatternsResorceName: '', + indexPatternsResourceName: '', currentUser: mockUser1, kibanaVersion: '8.8.0', }; diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/index.test.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/index.test.ts index fa27331f6c6c5..4838c70882f19 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/index.test.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/index.test.ts @@ -30,7 +30,7 @@ describe('AIAssistantDataClient', () => { logger, elasticsearchClientPromise: Promise.resolve(clusterClient), spaceId: 'default', - indexPatternsResorceName: '.kibana-elastic-ai-assistant-conversations', + indexPatternsResourceName: '.kibana-elastic-ai-assistant-conversations', currentUser: mockUser1, kibanaVersion: '8.8.0', }; diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/index.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/index.ts index 75f2b166f1468..5bc84e05c8087 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/index.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/index.ts @@ -21,7 +21,7 @@ export interface AIAssistantDataClientParams { kibanaVersion: string; spaceId: string; logger: Logger; - indexPatternsResorceName: string; + indexPatternsResourceName: string; currentUser: AuthenticatedUser | null; } @@ -38,7 +38,7 @@ export class AIAssistantDataClient { constructor(public readonly options: AIAssistantDataClientParams) { this.indexTemplateAndPattern = getIndexTemplateAndPattern( - this.options.indexPatternsResorceName, + this.options.indexPatternsResourceName, this.options.spaceId ?? DEFAULT_NAMESPACE_STRING ); this.currentUser = this.options.currentUser; diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/create_knowledge_base_entry.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/create_knowledge_base_entry.ts new file mode 100644 index 0000000000000..5430bf597ebe7 --- /dev/null +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/create_knowledge_base_entry.ts @@ -0,0 +1,83 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { v4 as uuidv4 } from 'uuid'; +import { ElasticsearchClient, Logger } from '@kbn/core/server'; + +import { + KnowledgeBaseEntryCreateProps, + KnowledgeBaseEntryResponse, +} from '@kbn/elastic-assistant-common'; +import { AuthenticatedUser } from '@kbn/security-plugin-types-common'; +import { getKnowledgeBaseEntry } from './get_knowledge_base_entry'; +import { CreateKnowledgeBaseEntrySchema } from './types'; + +export interface CreateKnowledgeBaseEntryParams { + esClient: ElasticsearchClient; + logger: Logger; + knowledgeBaseIndex: string; + spaceId: string; + user: AuthenticatedUser; + knowledgeBaseEntry: KnowledgeBaseEntryCreateProps; +} + +export const createKnowledgeBaseEntry = async ({ + esClient, + knowledgeBaseIndex, + spaceId, + user, + knowledgeBaseEntry, + logger, +}: CreateKnowledgeBaseEntryParams): Promise => { + const createdAt = new Date().toISOString(); + const body = transformToCreateSchema(createdAt, spaceId, user, knowledgeBaseEntry); + try { + const response = await esClient.create({ + body, + id: uuidv4(), + index: knowledgeBaseIndex, + refresh: 'wait_for', + }); + + return await getKnowledgeBaseEntry({ + esClient, + knowledgeBaseIndex, + id: response._id, + logger, + user, + }); + } catch (err) { + logger.error( + `Error creating Knowledge Base Entry: ${err} with kbResource: ${knowledgeBaseEntry.metadata.kbResource}` + ); + throw err; + } +}; + +export const transformToCreateSchema = ( + createdAt: string, + spaceId: string, + user: AuthenticatedUser, + { metadata, text }: KnowledgeBaseEntryCreateProps +): CreateKnowledgeBaseEntrySchema => { + return { + '@timestamp': createdAt, + created_at: createdAt, + created_by: user.profile_uid ?? 'unknown', + updated_at: createdAt, + updated_by: user.profile_uid ?? 'unknown', + users: [ + { + id: user.profile_uid, + name: user.username, + }, + ], + namespace: spaceId, + metadata, + text, + }; +}; diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/field_maps_configuration.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/field_maps_configuration.ts new file mode 100644 index 0000000000000..16b5b35a9b2bb --- /dev/null +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/field_maps_configuration.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 { FieldMap } from '@kbn/data-stream-adapter'; + +export const knowledgeBaseFieldMap: FieldMap = { + '@timestamp': { + type: 'date', + array: false, + required: false, + }, + id: { + type: 'keyword', + array: false, + required: true, + }, + created_at: { + type: 'date', + array: false, + required: false, + }, + created_by: { + type: 'keyword', + array: false, + required: false, + }, + updated_at: { + type: 'date', + array: false, + required: false, + }, + updated_by: { + type: 'keyword', + array: false, + required: false, + }, + users: { + type: 'nested', + array: true, + required: false, + }, + 'users.id': { + type: 'keyword', + array: false, + required: true, + }, + 'users.name': { + type: 'keyword', + array: false, + required: false, + }, + metadata: { + type: 'object', + array: false, + required: false, + }, + 'metadata.kbResource': { + type: 'keyword', + array: false, + required: false, + }, + 'metadata.required': { + type: 'boolean', + array: false, + required: false, + }, + 'metadata.source': { + type: 'keyword', + array: false, + required: false, + }, + text: { + type: 'text', + array: false, + required: true, + }, + vector: { + type: 'object', + array: false, + required: false, + }, + 'vector.tokens': { + type: 'rank_features', + array: false, + required: false, + }, +} as const; diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/get_knowledge_base_entry.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/get_knowledge_base_entry.ts new file mode 100644 index 0000000000000..c021e022765d0 --- /dev/null +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/get_knowledge_base_entry.ts @@ -0,0 +1,78 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ElasticsearchClient, Logger } from '@kbn/core/server'; +import { KnowledgeBaseEntryResponse } from '@kbn/elastic-assistant-common'; +import { AuthenticatedUser } from '@kbn/security-plugin/common'; +import { EsKnowledgeBaseEntrySchema } from './types'; +import { transformESSearchToKnowledgeBaseEntry } from './transforms'; + +export interface GetKnowledgeBaseEntryParams { + esClient: ElasticsearchClient; + logger: Logger; + knowledgeBaseIndex: string; + id: string; + user: AuthenticatedUser; +} + +export const getKnowledgeBaseEntry = async ({ + esClient, + logger, + knowledgeBaseIndex, + id, + user, +}: GetKnowledgeBaseEntryParams): Promise => { + const filterByUser = [ + { + nested: { + path: 'users', + query: { + bool: { + must: [ + { + match: user.profile_uid + ? { 'users.id': user.profile_uid } + : { 'users.name': user.username }, + }, + ], + }, + }, + }, + }, + ]; + try { + const response = await esClient.search({ + query: { + bool: { + must: [ + { + bool: { + should: [ + { + term: { + _id: id, + }, + }, + ], + }, + }, + ...filterByUser, + ], + }, + }, + _source: true, + ignore_unavailable: true, + index: knowledgeBaseIndex, + seq_no_primary_term: true, + }); + const knowledgeBaseEntry = transformESSearchToKnowledgeBaseEntry(response); + return knowledgeBaseEntry[0] ?? null; + } catch (err) { + logger.error(`Error fetching knowledge base entry: ${err} with id: ${id}`); + throw err; + } +}; diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/helpers.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/helpers.ts new file mode 100644 index 0000000000000..dc7f64e1aeee1 --- /dev/null +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/helpers.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { errors } from '@elastic/elasticsearch'; + +export const isModelAlreadyExistsError = (error: Error) => { + return ( + error instanceof errors.ResponseError && + (error.body.error.type === 'resource_not_found_exception' || + error.body.error.type === 'status_exception') + ); +}; diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/index.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/index.ts new file mode 100644 index 0000000000000..771ec35c07c51 --- /dev/null +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/index.ts @@ -0,0 +1,264 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + MlTrainedModelDeploymentNodesStats, + MlTrainedModelStats, +} from '@elastic/elasticsearch/lib/api/types'; +import type { MlPluginSetup } from '@kbn/ml-plugin/server'; +import type { KibanaRequest } from '@kbn/core-http-server'; +import type { Document } from 'langchain/document'; +import type { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; +import { KnowledgeBaseEntryResponse } from '@kbn/elastic-assistant-common'; +import pRetry from 'p-retry'; +import { AIAssistantDataClient, AIAssistantDataClientParams } from '..'; +import { ElasticsearchStore } from '../../lib/langchain/elasticsearch_store/elasticsearch_store'; +import { loadESQL } from '../../lib/langchain/content_loaders/esql_loader'; +import { GetElser } from '../../types'; +import { transformToCreateSchema } from './create_knowledge_base_entry'; +import { EsKnowledgeBaseEntrySchema } from './types'; +import { transformESSearchToKnowledgeBaseEntry } from './transforms'; +import { ESQL_DOCS_LOADED_QUERY } from '../../routes/knowledge_base/constants'; +import { isModelAlreadyExistsError } from './helpers'; + +interface KnowledgeBaseDataClientParams extends AIAssistantDataClientParams { + ml: MlPluginSetup; + getElserId: GetElser; + getIsKBSetupInProgress: () => boolean; + ingestPipelineResourceName: string; + setIsKBSetupInProgress: (isInProgress: boolean) => void; +} +export class AIAssistantKnowledgeBaseDataClient extends AIAssistantDataClient { + constructor(public readonly options: KnowledgeBaseDataClientParams) { + super(options); + } + + public get isSetupInProgress() { + return this.options.getIsKBSetupInProgress(); + } + + /** + * Downloads and installs ELSER model if not already installed + * + * @param soClient SavedObjectsClientContract for installing ELSER so that ML SO's are in sync + */ + private installModel = async ({ soClient }: { soClient: SavedObjectsClientContract }) => { + const elserId = await this.options.getElserId(); + this.options.logger.debug(`Installing ELSER model '${elserId}'...`); + + try { + await this.options.ml + // TODO: Potentially plumb soClient through DataClient from pluginStart + .trainedModelsProvider({} as KibanaRequest, soClient) + .installElasticModel(elserId); + } catch (error) { + this.options.logger.error(`Error installing ELSER model '${elserId}':\n${error}`); + } + }; + + /** + * Returns whether ELSER is installed/ready to deploy + * + * @returns Promise indicating whether the model is installed + */ + public isModelInstalled = async (): Promise => { + const elserId = await this.options.getElserId(); + this.options.logger.debug(`Checking if ELSER model '${elserId}' is installed...`); + + try { + const esClient = await this.options.elasticsearchClientPromise; + const getResponse = await esClient.ml.getTrainedModels({ + model_id: elserId, + include: 'definition_status', + }); + return Boolean(getResponse.trained_model_configs[0]?.fully_defined); + } catch (error) { + if (!isModelAlreadyExistsError(error)) { + this.options.logger.error( + `Error checking if ELSER model '${elserId}' is installed:\n${error}` + ); + } + return false; + } + }; + + /** + * Deploy the ELSER model with default configuration + */ + private deployModel = async () => { + const elserId = await this.options.getElserId(); + this.options.logger.debug(`Deploying ELSER model '${elserId}'...`); + try { + const esClient = await this.options.elasticsearchClientPromise; + await esClient.ml.startTrainedModelDeployment({ + model_id: elserId, + wait_for: 'fully_allocated', + }); + } catch (error) { + if (!isModelAlreadyExistsError(error)) { + this.options.logger.error(`Error deploying ELSER model '${elserId}':\n${error}`); + } + this.options.logger.debug(`Error deploying ELSER model '${elserId}', model already deployed`); + } + }; + + /** + * Checks if the provided model is deployed and allocated in Elasticsearch + * + * @returns Promise indicating whether the model is deployed + */ + public isModelDeployed = async (): Promise => { + const elserId = await this.options.getElserId(); + this.options.logger.debug(`Checking if ELSER model '${elserId}' is deployed...`); + + try { + const esClient = await this.options.elasticsearchClientPromise; + const getResponse = await esClient.ml.getTrainedModelsStats({ + model_id: elserId, + }); + + // For standardized way of checking deployment status see: https://github.com/elastic/elasticsearch/issues/106986 + const isReadyESS = (stats: MlTrainedModelStats) => + stats.deployment_stats?.state === 'started' && + stats.deployment_stats?.allocation_status.state === 'fully_allocated'; + + const isReadyServerless = (stats: MlTrainedModelStats) => + (stats.deployment_stats?.nodes as unknown as MlTrainedModelDeploymentNodesStats[]).some( + (node) => node.routing_state.routing_state === 'started' + ); + + return getResponse.trained_model_stats.some( + (stats) => isReadyESS(stats) || isReadyServerless(stats) + ); + } catch (e) { + // Returns 404 if it doesn't exist + return false; + } + }; + + /** + * Downloads and deploys recommended ELSER (if not already), then loads ES|QL docs + * + * NOTE: Before automatically installing ELSER in the background, we should perform deployment resource checks + * Only necessary for ESS, as Serverless can always auto-install if `productTier === complete` + * See ml-team issue for providing 'dry run' flag to perform these checks: https://github.com/elastic/ml-team/issues/1208 + * + * @param options + * @param options.esStore ElasticsearchStore for loading ES|QL docs via LangChain loaders + * @param options.soClient SavedObjectsClientContract for installing ELSER so that ML SO's are in sync + * + * @returns Promise + */ + public setupKnowledgeBase = async ({ + esStore, + soClient, + }: { + esStore: ElasticsearchStore; + soClient: SavedObjectsClientContract; + }): Promise => { + if (this.options.getIsKBSetupInProgress()) { + this.options.logger.debug('Knowledge Base setup already in progress'); + return; + } + + this.options.logger.debug('Starting Knowledge Base setup...'); + this.options.setIsKBSetupInProgress(true); + const elserId = await this.options.getElserId(); + + try { + const isInstalled = await this.isModelInstalled(); + if (!isInstalled) { + await this.installModel({ soClient }); + await pRetry( + async () => + (await this.isModelInstalled()) + ? Promise.resolve() + : Promise.reject(new Error('Model not installed')), + { minTimeout: 10000, maxTimeout: 10000, retries: 10 } + ); + this.options.logger.debug(`ELSER model '${elserId}' successfully installed!`); + } else { + this.options.logger.debug(`ELSER model '${elserId}' is already installed`); + } + + const isDeployed = await this.isModelDeployed(); + if (!isDeployed) { + await this.deployModel(); + await pRetry( + async () => + (await this.isModelDeployed()) + ? Promise.resolve() + : Promise.reject(new Error('Model not deployed')), + { minTimeout: 2000, retries: 10 } + ); + this.options.logger.debug(`ELSER model '${elserId}' successfully deployed!`); + } else { + this.options.logger.debug(`ELSER model '${elserId}' is already deployed`); + } + + this.options.logger.debug(`Checking if Knowledge Base docs have been loaded...`); + const kbDocsLoaded = (await esStore.similaritySearch(ESQL_DOCS_LOADED_QUERY)).length > 0; + if (!kbDocsLoaded) { + this.options.logger.debug(`Loading KB docs...`); + await loadESQL(esStore, this.options.logger); + } else { + this.options.logger.debug(`Knowledge Base docs already loaded!`); + } + } catch (e) { + this.options.logger.error(`Error setting up Knowledge Base: ${e.message}`); + } + this.options.setIsKBSetupInProgress(false); + }; + + /** + * Adds LangChain Documents to the knowledge base + * + * @param documents + * @param authenticatedUser + */ + public addKnowledgeBaseDocuments = async ({ + documents, + }: { + documents: Document[]; + }): Promise => { + const writer = await this.getWriter(); + const changedAt = new Date().toISOString(); + const authenticatedUser = this.options.currentUser; + if (authenticatedUser == null) { + throw new Error( + 'Authenticated user not found! Ensure kbDataClient was initialized from a request.' + ); + } + // @ts-ignore + const { errors, docs_created: docsCreated } = await writer.bulk({ + documentsToCreate: documents.map((doc) => + transformToCreateSchema(changedAt, this.spaceId, authenticatedUser, { + // TODO: Update the LangChain Document Metadata type extension + metadata: { + kbResource: doc.metadata.kbResourcer ?? 'unknown', + required: doc.metadata.required ?? false, + source: doc.metadata.source ?? 'unknown', + }, + text: doc.pageContent, + }) + ), + authenticatedUser, + }); + const created = + docsCreated.length > 0 + ? await this.findDocuments({ + page: 1, + perPage: 10000, + filter: docsCreated.map((c) => `_id:${c}`).join(' OR '), + }) + : undefined; + this.options.logger.debug(`created: ${created?.data.hits.hits.length ?? '0'}`); + this.options.logger.debug(`errors: ${JSON.stringify(errors, null, 2)}`); + + return created?.data ? transformESSearchToKnowledgeBaseEntry(created?.data) : []; + }; +} diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/ingest_pipeline.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/ingest_pipeline.ts new file mode 100644 index 0000000000000..170fa0342f9d9 --- /dev/null +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/ingest_pipeline.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { IngestPutPipelineRequest } from '@elastic/elasticsearch/lib/api/types'; + +export const knowledgeBaseIngestPipeline = ({ + id, + modelId, +}: { + id: string; + modelId: string; +}): IngestPutPipelineRequest => ({ + id, + description: 'Embedding pipeline for Elastic AI Assistant ELSER Knowledge Base', + processors: [ + { + inference: { + model_id: modelId, + target_field: 'vector', + field_map: { + text: 'text_field', + }, + inference_config: { + // @ts-expect-error + text_expansion: { + results_field: 'tokens', + }, + }, + }, + }, + ], +}); diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/transforms.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/transforms.ts new file mode 100644 index 0000000000000..f185c5ba8fdc2 --- /dev/null +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/transforms.ts @@ -0,0 +1,96 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { estypes } from '@elastic/elasticsearch'; +import { KnowledgeBaseEntryResponse } from '@kbn/elastic-assistant-common'; +import { EsKnowledgeBaseEntrySchema } from './types'; + +export const transformESSearchToKnowledgeBaseEntry = ( + response: estypes.SearchResponse +): KnowledgeBaseEntryResponse[] => { + return response.hits.hits + .filter((hit) => hit._source !== undefined) + .map((hit) => { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const kbEntrySchema = hit._source!; + const kbEntry: KnowledgeBaseEntryResponse = { + timestamp: kbEntrySchema['@timestamp'], + id: hit._id, + createdAt: kbEntrySchema.created_at, + createdBy: kbEntrySchema.created_by, + updatedAt: kbEntrySchema.updated_at, + updatedBy: kbEntrySchema.updated_by, + users: + kbEntrySchema.users?.map((user) => ({ + id: user.id, + name: user.name, + })) ?? [], + ...(kbEntrySchema.metadata + ? { + metadata: { + kbResource: kbEntrySchema.metadata.kbResource, + source: kbEntrySchema.metadata.source, + required: kbEntrySchema.metadata.required, + }, + } + : {}), + namespace: kbEntrySchema.namespace, + text: kbEntrySchema.text, + ...(kbEntrySchema.vector + ? { + vector: { + modelId: kbEntrySchema.vector.model_id, + tokens: kbEntrySchema.vector.tokens, + }, + } + : {}), + }; + + return kbEntry; + }); +}; + +export const transformESToKnowledgeBase = ( + response: EsKnowledgeBaseEntrySchema[] +): KnowledgeBaseEntryResponse[] => { + return response.map((kbEntrySchema) => { + const kbEntry: KnowledgeBaseEntryResponse = { + timestamp: kbEntrySchema['@timestamp'], + id: kbEntrySchema.id, + createdAt: kbEntrySchema.created_at, + createdBy: kbEntrySchema.created_by, + updatedAt: kbEntrySchema.updated_at, + updatedBy: kbEntrySchema.updated_by, + users: + kbEntrySchema.users?.map((user) => ({ + id: user.id, + name: user.name, + })) ?? [], + ...(kbEntrySchema.metadata + ? { + metadata: { + kbResource: kbEntrySchema.metadata.kbResource, + source: kbEntrySchema.metadata.source, + required: kbEntrySchema.metadata.required, + }, + } + : {}), + namespace: kbEntrySchema.namespace, + text: kbEntrySchema.text, + ...(kbEntrySchema.vector + ? { + vector: { + modelId: kbEntrySchema.vector.model_id, + tokens: kbEntrySchema.vector.tokens, + }, + } + : {}), + }; + + return kbEntry; + }); +}; diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/types.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/types.ts new file mode 100644 index 0000000000000..b3180d80223ce --- /dev/null +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/types.ts @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export interface EsKnowledgeBaseEntrySchema { + '@timestamp': string; + id: string; + created_at: string; + created_by: string; + updated_at: string; + updated_by: string; + users?: Array<{ + id?: string; + name?: string; + }>; + metadata?: { + kbResource: string; + source: string; + required: boolean; + }; + namespace: string; + text: string; + vector?: { + tokens: Record; + model_id: string; + }; +} + +export interface CreateKnowledgeBaseEntrySchema { + '@timestamp'?: string; + id?: string | undefined; + created_at: string; + created_by: string; + updated_at: string; + updated_by: string; + users: Array<{ + id?: string; + name?: string; + }>; + metadata?: { + kbResource: string; + source: string; + required: boolean; + }; + namespace: string; + text: string; + vector?: { + tokens: Record; + model_id: string; + }; +} diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_service/helpers.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_service/helpers.ts new file mode 100644 index 0000000000000..8503494cf1535 --- /dev/null +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_service/helpers.ts @@ -0,0 +1,111 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import { once } from 'lodash/fp'; +import type { KibanaRequest } from '@kbn/core-http-server'; +import type { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; +import type { MlPluginSetup } from '@kbn/ml-plugin/server'; +import { knowledgeBaseIngestPipeline } from '../ai_assistant_data_clients/knowledge_base/ingest_pipeline'; +import { GetElser } from '../types'; + +/** + * Creates a function that returns the ELSER model ID + * + * @param ml + */ +export const createGetElserId = (ml: MlPluginSetup): GetElser => { + return once(async () => { + return ( + ( + await ml + // Force check to happen as internal user + .trainedModelsProvider({} as KibanaRequest, {} as SavedObjectsClientContract) + .getELSER() + ).model_id + ); + }); +}; + +interface PipelineExistsParams { + esClient: ElasticsearchClient; + id: string; +} + +/** + * Checks if the provided ingest pipeline exists in Elasticsearch + * + * @param params params + * @param params.esClient Elasticsearch client with privileges to check for ingest pipelines + * @param params.id ID of the ingest pipeline to check + * + * @returns Promise indicating whether the pipeline exists + */ +export const pipelineExists = async ({ esClient, id }: PipelineExistsParams): Promise => { + try { + const response = await esClient.ingest.getPipeline({ + id, + }); + return Object.keys(response).length > 0; + } catch (e) { + // The GET /_ingest/pipeline/{pipelineId} API returns an empty object w/ 404 Not Found. + return false; + } +}; + +interface CreatePipelineParams { + esClient: ElasticsearchClient; + id: string; + modelId: string; +} + +/** + * Create ingest pipeline for ELSER in Elasticsearch + * + * @param params params + * @param params.esClient Elasticsearch client with privileges to check for ingest pipelines + * @param params.id ID of the ingest pipeline + * @param params.modelId ID of the ELSER model + * + * @returns Promise indicating whether the pipeline was created + */ +export const createPipeline = async ({ + esClient, + id, + modelId, +}: CreatePipelineParams): Promise => { + try { + const response = await esClient.ingest.putPipeline( + knowledgeBaseIngestPipeline({ + id, + modelId, + }) + ); + + return response.acknowledged; + } catch (e) { + return false; + } +}; + +interface DeletePipelineParams { + esClient: ElasticsearchClient; + id: string; +} + +/** + * Delete ingest pipeline for ELSER in Elasticsearch + * + * @returns Promise indicating whether the pipeline was created + */ +export const deletePipeline = async ({ esClient, id }: DeletePipelineParams): Promise => { + const response = await esClient.ingest.deletePipeline({ + id, + }); + + return response.acknowledged; +}; 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 a96088b413dcf..dbdc01dcf9e57 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 @@ -14,8 +14,10 @@ import { AuthenticatedUser } from '@kbn/security-plugin/server'; import { DEFAULT_NAMESPACE_STRING } from '@kbn/core-saved-objects-utils-server'; import { conversationsDataClientMock } from '../__mocks__/data_clients.mock'; import { AIAssistantConversationsDataClient } from '../ai_assistant_data_clients/conversations'; -import { AIAssistantService } from '.'; +import { AIAssistantService, AIAssistantServiceOpts } from '.'; import { retryUntil } from './create_resource_installation_helper.test'; +import { mlPluginMock } from '@kbn/ml-plugin/public/mocks'; +import type { MlPluginSetup } from '@kbn/ml-plugin/server'; jest.mock('../ai_assistant_data_clients/conversations', () => ({ AIAssistantConversationsDataClient: jest.fn(), @@ -95,6 +97,7 @@ const mockUser1 = { describe('AI Assistant Service', () => { let pluginStop$: Subject; + let assistantServiceOpts: AIAssistantServiceOpts; beforeEach(() => { jest.resetAllMocks(); @@ -107,6 +110,14 @@ describe('AI Assistant Service', () => { ); clusterClient.indices.getAlias.mockImplementation(async () => GetAliasResponse); clusterClient.indices.getDataStream.mockImplementation(async () => GetDataStreamResponse); + assistantServiceOpts = { + logger, + elasticsearchClientPromise: Promise.resolve(clusterClient), + pluginStop$, + kibanaVersion: '8.8.0', + ml: mlPluginMock.createSetupContract() as unknown as MlPluginSetup, // Missing SharedServices mock + taskManager: taskManagerMock.createSetup(), + }; }); afterEach(() => { @@ -116,13 +127,7 @@ describe('AI Assistant Service', () => { describe('AIAssistantService()', () => { test('should correctly initialize common resources', async () => { - const assistantService = new AIAssistantService({ - logger, - elasticsearchClientPromise: Promise.resolve(clusterClient), - pluginStop$, - kibanaVersion: '8.8.0', - taskManager: taskManagerMock.createSetup(), - }); + const assistantService = new AIAssistantService(assistantServiceOpts); await retryUntil( 'AI Assistant service initialized', @@ -140,13 +145,7 @@ describe('AI Assistant Service', () => { test('should log error and set initialized to false if creating/updating common component template throws error', async () => { clusterClient.cluster.putComponentTemplate.mockRejectedValueOnce(new Error('fail')); - const assistantService = new AIAssistantService({ - logger, - elasticsearchClientPromise: Promise.resolve(clusterClient), - pluginStop$, - kibanaVersion: '8.8.0', - taskManager: taskManagerMock.createSetup(), - }); + const assistantService = new AIAssistantService(assistantServiceOpts); await retryUntil('error log called', async () => logger.error.mock.calls.length > 0); @@ -169,13 +168,7 @@ describe('AI Assistant Service', () => { }); test('should create new AIAssistantConversationsDataClient', async () => { - assistantService = new AIAssistantService({ - logger, - elasticsearchClientPromise: Promise.resolve(clusterClient), - pluginStop$, - kibanaVersion: '8.8.0', - taskManager: taskManagerMock.createSetup(), - }); + assistantService = new AIAssistantService(assistantServiceOpts); await retryUntil( 'AI Assistant service initialized', @@ -192,7 +185,7 @@ describe('AI Assistant Service', () => { logger, elasticsearchClientPromise: Promise.resolve(clusterClient), spaceId: 'default', - indexPatternsResorceName: '.kibana-elastic-ai-assistant-conversations', + indexPatternsResourceName: '.kibana-elastic-ai-assistant-conversations', currentUser: mockUser1, kibanaVersion: '8.8.0', }); @@ -201,13 +194,7 @@ describe('AI Assistant Service', () => { test('should retry initializing common resources if common resource initialization failed', async () => { clusterClient.cluster.putComponentTemplate.mockRejectedValueOnce(new Error('fail')); - assistantService = new AIAssistantService({ - logger, - elasticsearchClientPromise: Promise.resolve(clusterClient), - pluginStop$, - kibanaVersion: '8.8.0', - taskManager: taskManagerMock.createSetup(), - }); + assistantService = new AIAssistantService(assistantServiceOpts); await retryUntil('error log called', async () => logger.error.mock.calls.length > 0); @@ -234,7 +221,7 @@ describe('AI Assistant Service', () => { logger, elasticsearchClientPromise: Promise.resolve(clusterClient), spaceId: 'default', - indexPatternsResorceName: '.kibana-elastic-ai-assistant-conversations', + indexPatternsResourceName: '.kibana-elastic-ai-assistant-conversations', currentUser: mockUser1, kibanaVersion: '8.8.0', }); @@ -259,13 +246,7 @@ describe('AI Assistant Service', () => { return { acknowledged: true }; }); - assistantService = new AIAssistantService({ - logger, - elasticsearchClientPromise: Promise.resolve(clusterClient), - pluginStop$, - kibanaVersion: '8.8.0', - taskManager: taskManagerMock.createSetup(), - }); + assistantService = new AIAssistantService(assistantServiceOpts); await retryUntil('error log called', async () => logger.error.mock.calls.length > 0); @@ -298,7 +279,7 @@ describe('AI Assistant Service', () => { expect(AIAssistantConversationsDataClient).toHaveBeenCalledWith({ elasticsearchClientPromise: Promise.resolve(clusterClient), spaceId: 'default', - indexPatternsResorceName: '.kibana-elastic-ai-assistant-conversations', + indexPatternsResourceName: '.kibana-elastic-ai-assistant-conversations', currentUser: mockUser1, kibanaVersion: '8.8.0', logger, @@ -336,13 +317,7 @@ describe('AI Assistant Service', () => { mappings: {}, }, })); - assistantService = new AIAssistantService({ - logger, - elasticsearchClientPromise: Promise.resolve(clusterClient), - pluginStop$, - kibanaVersion: '8.8.0', - taskManager: taskManagerMock.createSetup(), - }); + assistantService = new AIAssistantService(assistantServiceOpts); await retryUntil( 'AI Assistant service initialized', @@ -358,7 +333,7 @@ describe('AI Assistant Service', () => { expect(AIAssistantConversationsDataClient).toHaveBeenCalledWith({ elasticsearchClientPromise: Promise.resolve(clusterClient), spaceId: 'default', - indexPatternsResorceName: '.kibana-elastic-ai-assistant-conversations', + indexPatternsResourceName: '.kibana-elastic-ai-assistant-conversations', currentUser: mockUser1, kibanaVersion: '8.8.0', logger, @@ -397,13 +372,7 @@ describe('AI Assistant Service', () => { return SimulateTemplateResponse; }); - assistantService = new AIAssistantService({ - logger, - elasticsearchClientPromise: Promise.resolve(clusterClient), - pluginStop$, - kibanaVersion: '8.8.0', - taskManager: taskManagerMock.createSetup(), - }); + assistantService = new AIAssistantService(assistantServiceOpts); await retryUntil( 'AI Assistant service initialized', @@ -431,7 +400,7 @@ describe('AI Assistant Service', () => { expect(AIAssistantConversationsDataClient).toHaveBeenCalledWith({ elasticsearchClientPromise: Promise.resolve(clusterClient), spaceId: 'default', - indexPatternsResorceName: '.kibana-elastic-ai-assistant-conversations', + indexPatternsResourceName: '.kibana-elastic-ai-assistant-conversations', currentUser: mockUser1, kibanaVersion: '8.8.0', logger, @@ -475,13 +444,7 @@ describe('AI Assistant Service', () => { }, })); - assistantService = new AIAssistantService({ - logger, - elasticsearchClientPromise: Promise.resolve(clusterClient), - pluginStop$, - kibanaVersion: '8.8.0', - taskManager: taskManagerMock.createSetup(), - }); + assistantService = new AIAssistantService(assistantServiceOpts); await retryUntil( 'AI Assistant service initialized', @@ -523,13 +486,7 @@ describe('AI Assistant Service', () => { throw new Error(`fail ${++failCount}`); }); - assistantService = new AIAssistantService({ - logger, - elasticsearchClientPromise: Promise.resolve(clusterClient), - pluginStop$, - kibanaVersion: '8.8.0', - taskManager: taskManagerMock.createSetup(), - }); + assistantService = new AIAssistantService(assistantServiceOpts); await retryUntil('error log called', async () => logger.error.mock.calls.length > 0, 1); @@ -574,13 +531,7 @@ describe('AI Assistant Service', () => { test('should return null if retrying common resources initialization fails again with same error', async () => { clusterClient.cluster.putComponentTemplate.mockRejectedValue(new Error('fail')); - assistantService = new AIAssistantService({ - logger, - elasticsearchClientPromise: Promise.resolve(clusterClient), - pluginStop$, - kibanaVersion: '8.8.0', - taskManager: taskManagerMock.createSetup(), - }); + assistantService = new AIAssistantService(assistantServiceOpts); await retryUntil('error log called', async () => logger.error.mock.calls.length > 0); @@ -633,13 +584,7 @@ describe('AI Assistant Service', () => { })); clusterClient.indices.putIndexTemplate.mockRejectedValue(new Error('fail index template')); - assistantService = new AIAssistantService({ - logger, - elasticsearchClientPromise: Promise.resolve(clusterClient), - pluginStop$, - kibanaVersion: '8.8.0', - taskManager: taskManagerMock.createSetup(), - }); + assistantService = new AIAssistantService(assistantServiceOpts); await retryUntil( 'AI Assistant service initialized', @@ -677,13 +622,7 @@ describe('AI Assistant Service', () => { .mockRejectedValueOnce(new EsErrors.ConnectionError('foo')) .mockRejectedValueOnce(new EsErrors.TimeoutError('timeout')) .mockResolvedValue({ acknowledged: true }); - const assistantService = new AIAssistantService({ - logger, - elasticsearchClientPromise: Promise.resolve(clusterClient), - pluginStop$, - kibanaVersion: '8.8.0', - taskManager: taskManagerMock.createSetup(), - }); + const assistantService = new AIAssistantService(assistantServiceOpts); await retryUntil( 'AI Assistant service initialized', @@ -697,13 +636,7 @@ describe('AI Assistant Service', () => { .mockRejectedValueOnce(new EsErrors.ConnectionError('foo')) .mockRejectedValueOnce(new EsErrors.TimeoutError('timeout')) .mockResolvedValue({ acknowledged: true }); - const assistantService = new AIAssistantService({ - logger, - elasticsearchClientPromise: Promise.resolve(clusterClient), - pluginStop$, - kibanaVersion: '8.8.0', - taskManager: taskManagerMock.createSetup(), - }); + const assistantService = new AIAssistantService(assistantServiceOpts); await retryUntil( 'AI Assistant service initialized', @@ -724,13 +657,7 @@ describe('AI Assistant Service', () => { .mockRejectedValueOnce(new EsErrors.ConnectionError('foo')) .mockRejectedValueOnce(new EsErrors.TimeoutError('timeout')) .mockResolvedValue({ acknowledged: true }); - const assistantService = new AIAssistantService({ - logger, - elasticsearchClientPromise: Promise.resolve(clusterClient), - pluginStop$, - kibanaVersion: '8.8.0', - taskManager: taskManagerMock.createSetup(), - }); + const assistantService = new AIAssistantService(assistantServiceOpts); await retryUntil( 'AI Assistant service initialized', @@ -750,13 +677,7 @@ describe('AI Assistant Service', () => { .mockRejectedValueOnce(new EsErrors.ConnectionError('foo')) .mockRejectedValueOnce(new EsErrors.TimeoutError('timeout')) .mockResolvedValue({ acknowledged: true }); - const assistantService = new AIAssistantService({ - logger, - elasticsearchClientPromise: Promise.resolve(clusterClient), - pluginStop$, - kibanaVersion: '8.8.0', - taskManager: taskManagerMock.createSetup(), - }); + const assistantService = new AIAssistantService(assistantServiceOpts); await retryUntil( 'AI Assistant service initialized', @@ -783,13 +704,7 @@ describe('AI Assistant Service', () => { hits: { hits: [], total: { value: 0 } }, }); - const assistantService = new AIAssistantService({ - logger, - elasticsearchClientPromise: Promise.resolve(clusterClient), - pluginStop$, - kibanaVersion: '8.8.0', - taskManager: taskManagerMock.createSetup(), - }); + const assistantService = new AIAssistantService(assistantServiceOpts); await retryUntil( 'AI Assistant service initialized', 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 9cc3efb03e195..619d9e9bca256 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 @@ -9,10 +9,11 @@ import { DataStreamSpacesAdapter, FieldMap } from '@kbn/data-stream-adapter'; import { DEFAULT_NAMESPACE_STRING } from '@kbn/core-saved-objects-utils-server'; import type { Logger, ElasticsearchClient } from '@kbn/core/server'; import type { TaskManagerSetupContract } from '@kbn/task-manager-plugin/server'; +import type { MlPluginSetup } from '@kbn/ml-plugin/server'; import { AuthenticatedUser } from '@kbn/security-plugin/server'; import { Subject } from 'rxjs'; import { getDefaultAnonymizationFields } from '../../common/anonymization'; -import { AssistantResourceNames } from '../types'; +import { AssistantResourceNames, GetElser } from '../types'; import { AIAssistantConversationsDataClient } from '../ai_assistant_data_clients/conversations'; import { InitializationPromise, @@ -25,6 +26,9 @@ import { conversationsFieldMap } from '../ai_assistant_data_clients/conversation import { assistantPromptsFieldMap } from '../ai_assistant_data_clients/prompts/field_maps_configuration'; import { assistantAnonymizationFieldsFieldMap } from '../ai_assistant_data_clients/anonymization_fields/field_maps_configuration'; import { AIAssistantDataClient } from '../ai_assistant_data_clients'; +import { knowledgeBaseFieldMap } from '../ai_assistant_data_clients/knowledge_base/field_maps_configuration'; +import { AIAssistantKnowledgeBaseDataClient } from '../ai_assistant_data_clients/knowledge_base'; +import { createGetElserId, createPipeline, pipelineExists } from './helpers'; const TOTAL_FIELDS_LIMIT = 2500; @@ -32,10 +36,11 @@ function getResourceName(resource: string) { return `.kibana-elastic-ai-assistant-${resource}`; } -interface AIAssistantServiceOpts { +export interface AIAssistantServiceOpts { logger: Logger; kibanaVersion: string; elasticsearchClientPromise: Promise; + ml: MlPluginSetup; taskManager: TaskManagerSetupContract; pluginStop$: Subject; } @@ -47,7 +52,7 @@ export interface CreateAIAssistantClientParams { } export type CreateDataStream = (params: { - resource: 'conversations' | 'prompts' | 'anonymizationFields'; + resource: 'anonymizationFields' | 'conversations' | 'knowledgeBase' | 'prompts'; fieldMap: FieldMap; kibanaVersion: string; spaceId?: string; @@ -55,20 +60,31 @@ 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; + private knowledgeBaseDataStream: DataStreamSpacesAdapter; private promptsDataStream: DataStreamSpacesAdapter; private anonymizationFieldsDataStream: DataStreamSpacesAdapter; private resourceInitializationHelper: ResourceInstallationHelper; private initPromise: Promise; + private isKBSetupInProgress: boolean = false; constructor(private readonly options: AIAssistantServiceOpts) { this.initialized = false; + this.getElserId = createGetElserId(options.ml); this.conversationsDataStream = this.createDataStream({ resource: 'conversations', kibanaVersion: options.kibanaVersion, fieldMap: conversationsFieldMap, }); + this.knowledgeBaseDataStream = this.createDataStream({ + resource: 'knowledgeBase', + kibanaVersion: options.kibanaVersion, + fieldMap: knowledgeBaseFieldMap, + }); this.promptsDataStream = this.createDataStream({ resource: 'prompts', kibanaVersion: options.kibanaVersion, @@ -93,6 +109,13 @@ export class AIAssistantService { return this.initialized; } + public getIsKBSetupInProgress() { + return this.isKBSetupInProgress; + } + public setIsKBSetupInProgress(isInProgress: boolean) { + this.isKBSetupInProgress = isInProgress; + } + private createDataStream: CreateDataStream = ({ resource, kibanaVersion, fieldMap }) => { const newDataStream = new DataStreamSpacesAdapter(this.resourceNames.aliases[resource], { kibanaVersion, @@ -107,6 +130,19 @@ export class AIAssistantService { newDataStream.setIndexTemplate({ name: this.resourceNames.indexTemplate[resource], componentTemplateRefs: [this.resourceNames.componentTemplate[resource]], + // Apply `default_pipeline` if pipeline exists for resource + ...(resource in this.resourceNames.pipelines + ? { + template: { + settings: { + 'index.default_pipeline': + this.resourceNames.pipelines[ + resource as keyof typeof this.resourceNames.pipelines + ], + }, + }, + } + : {}), }); return newDataStream; @@ -124,6 +160,36 @@ export class AIAssistantService { pluginStop$: this.options.pluginStop$, }); + if (this.initializeKnowledgeBase) { + 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({ + 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(), + }); + + 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({ esClient, logger: this.options.logger, @@ -149,30 +215,30 @@ export class AIAssistantService { private readonly resourceNames: AssistantResourceNames = { componentTemplate: { conversations: getResourceName('component-template-conversations'), + knowledgeBase: getResourceName('component-template-knowledge-base'), prompts: getResourceName('component-template-prompts'), anonymizationFields: getResourceName('component-template-anonymization-fields'), - kb: getResourceName('component-template-kb'), }, aliases: { conversations: getResourceName('conversations'), + knowledgeBase: getResourceName('knowledge-base'), prompts: getResourceName('prompts'), anonymizationFields: getResourceName('anonymization-fields'), - kb: getResourceName('kb'), }, indexPatterns: { conversations: getResourceName('conversations*'), + knowledgeBase: getResourceName('knowledge-base*'), prompts: getResourceName('prompts*'), anonymizationFields: getResourceName('anonymization-fields*'), - kb: getResourceName('kb*'), }, indexTemplate: { conversations: getResourceName('index-template-conversations'), + knowledgeBase: getResourceName('index-template-knowledge-base'), prompts: getResourceName('index-template-prompts'), anonymizationFields: getResourceName('index-template-anonymization-fields'), - kb: getResourceName('index-template-kb'), }, pipelines: { - kb: getResourceName('kb-ingest-pipeline'), + knowledgeBase: getResourceName('ingest-pipeline-knowledge-base'), }, }; @@ -182,7 +248,7 @@ export class AIAssistantService { opts.spaceId ); - // If space evel resources initialization failed, retry + // If space level resources initialization failed, retry if (!initialized && error) { let initRetryPromise: Promise | undefined; @@ -236,11 +302,42 @@ export class AIAssistantService { elasticsearchClientPromise: this.options.elasticsearchClientPromise, spaceId: opts.spaceId, kibanaVersion: this.options.kibanaVersion, - indexPatternsResorceName: this.resourceNames.aliases.conversations, + indexPatternsResourceName: this.resourceNames.aliases.conversations, currentUser: opts.currentUser, }); } + public async createAIAssistantKnowledgeBaseDataClient( + opts: CreateAIAssistantClientParams & { initializeKnowledgeBase: boolean } + ): 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) { + return null; + } + + return new AIAssistantKnowledgeBaseDataClient({ + logger: this.options.logger.get('knowledgeBase'), + currentUser: opts.currentUser, + elasticsearchClientPromise: this.options.elasticsearchClientPromise, + indexPatternsResourceName: this.resourceNames.aliases.knowledgeBase, + ingestPipelineResourceName: this.resourceNames.pipelines.knowledgeBase, + getElserId: this.getElserId, + getIsKBSetupInProgress: this.getIsKBSetupInProgress.bind(this), + kibanaVersion: this.options.kibanaVersion, + ml: this.options.ml, + setIsKBSetupInProgress: this.setIsKBSetupInProgress.bind(this), + spaceId: opts.spaceId, + }); + } + public async createAIAssistantPromptsDataClient( opts: CreateAIAssistantClientParams ): Promise { @@ -255,7 +352,7 @@ export class AIAssistantService { elasticsearchClientPromise: this.options.elasticsearchClientPromise, spaceId: opts.spaceId, kibanaVersion: this.options.kibanaVersion, - indexPatternsResorceName: this.resourceNames.aliases.prompts, + indexPatternsResourceName: this.resourceNames.aliases.prompts, currentUser: opts.currentUser, }); } @@ -274,7 +371,7 @@ export class AIAssistantService { elasticsearchClientPromise: this.options.elasticsearchClientPromise, spaceId: opts.spaceId, kibanaVersion: this.options.kibanaVersion, - indexPatternsResorceName: this.resourceNames.aliases.anonymizationFields, + indexPatternsResourceName: this.resourceNames.aliases.anonymizationFields, currentUser: opts.currentUser, }); } @@ -308,6 +405,15 @@ 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 promptsIndexName = await this.promptsDataStream.getInstalledSpaceName(spaceId); if (!promptsIndexName) { await this.promptsDataStream.installSpace(spaceId); @@ -334,7 +440,7 @@ export class AIAssistantService { elasticsearchClientPromise: this.options.elasticsearchClientPromise, spaceId, kibanaVersion: this.options.kibanaVersion, - indexPatternsResorceName: this.resourceNames.aliases.anonymizationFields, + indexPatternsResourceName: this.resourceNames.aliases.anonymizationFields, currentUser: null, }); 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 83b4227275066..3cae3972c8bf6 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 @@ -5,7 +5,6 @@ * 2.0. */ -import { v4 as uuidV4 } from 'uuid'; import type { BulkOperationContainer, BulkOperationType, @@ -241,7 +240,8 @@ export class DocumentsDataWriter implements DocumentsDataWriter { ): Promise => { const documentCreateBody = params.documentsToCreate ? params.documentsToCreate.flatMap((document) => [ - { create: { _index: this.options.index, _id: uuidV4() } }, + // Do not pre-gen _id for bulk create operations to avoid `version_conflict_engine_exception` + { create: { _index: this.options.index } }, document, ]) : []; diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.ts index ae6540de5e271..86791cec5f5ce 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/elasticsearch_store/elasticsearch_store.ts @@ -34,6 +34,7 @@ import { KNOWLEDGE_BASE_EXECUTION_ERROR_EVENT, KNOWLEDGE_BASE_EXECUTION_SUCCESS_EVENT, } from '../../telemetry/event_based_telemetry'; +import { AIAssistantKnowledgeBaseDataClient } from '../../../ai_assistant_data_clients/knowledge_base'; interface CreatePipelineParams { id?: string; @@ -64,8 +65,8 @@ export const TERMS_QUERY_SIZE = 10000; export class ElasticsearchStore extends VectorStore { declare FilterType: QueryDslQueryContainer; - // Note: convert to { Client } from '@elastic/elasticsearch' for langchain contribution (removing Kibana dependency) private readonly esClient: ElasticsearchClient; + private readonly kbDataClient: AIAssistantKnowledgeBaseDataClient | undefined; private readonly index: string; private readonly logger: Logger; private readonly telemetry: AnalyticsServiceSetup; @@ -82,7 +83,8 @@ export class ElasticsearchStore extends VectorStore { logger: Logger, telemetry: AnalyticsServiceSetup, model?: string, - kbResource?: string | undefined + kbResource?: string | undefined, + kbDataClient?: AIAssistantKnowledgeBaseDataClient ) { super(new ElasticsearchEmbeddings(logger), { esClient, index }); this.esClient = esClient; @@ -91,6 +93,7 @@ export class ElasticsearchStore extends VectorStore { this.telemetry = telemetry; this.model = model ?? '.elser_model_2'; this.kbResource = kbResource ?? ESQL_RESOURCE; + this.kbDataClient = kbDataClient; } /** @@ -105,14 +108,16 @@ export class ElasticsearchStore extends VectorStore { documents: Document[], options?: Record ): Promise => { + // Code path for when `assistantKnowledgeBaseByDefault` FF is enabled + // Once removed replace addDocuments() w/ addDocumentsViaDataClient() + if (this.kbDataClient != null) { + return this.addDocumentsViaDataClient(documents, options); + } + const pipelineExists = await this.pipelineExists(); if (!pipelineExists) { await this.createPipeline(); } - const indexExists = await this.indexExists(); - if (!indexExists) { - await this.createIndex(); - } const operations = documents.flatMap(({ pageContent, metadata }) => [ { index: { _index: this.index, _id: uuid.v4() } }, @@ -139,6 +144,26 @@ export class ElasticsearchStore extends VectorStore { } }; + addDocumentsViaDataClient = async ( + documents: Document[], + options?: Record + ): Promise => { + if (!this.kbDataClient) { + this.logger.error('No kbDataClient provided'); + return []; + } + + try { + const response = await this.kbDataClient.addKnowledgeBaseDocuments({ + documents, + }); + return response.map((doc) => doc.id); + } catch (e) { + this.logger.error(`Error loading data into KB\n ${e}`); + return []; + } + }; + /** * Add vectors to the store. Returns a list of document IDs. * @@ -317,6 +342,13 @@ export class ElasticsearchStore extends VectorStore { * @returns Promise indicating whether the index was created */ deleteIndex = async (index?: string): Promise => { + // Code path for when `assistantKnowledgeBaseByDefault` FF is enabled + // We won't be supporting delete operations for the KB data stream going forward, so this can be removed along with the FF + if (this.kbDataClient != null) { + const response = await this.esClient.indices.deleteDataStream({ name: index ?? this.index }); + return response.acknowledged; + } + const response = await this.esClient.indices.delete({ index: index ?? this.index, }); @@ -332,8 +364,12 @@ export class ElasticsearchStore extends VectorStore { */ pipelineExists = async (pipelineId?: string): Promise => { try { + const id = + pipelineId ?? + this.kbDataClient?.options.ingestPipelineResourceName ?? + KNOWLEDGE_BASE_INGEST_PIPELINE; const response = await this.esClient.ingest.getPipeline({ - id: KNOWLEDGE_BASE_INGEST_PIPELINE, + id, }); return Object.keys(response).length > 0; } catch (e) { @@ -349,7 +385,10 @@ export class ElasticsearchStore extends VectorStore { */ createPipeline = async ({ id, description }: CreatePipelineParams = {}): Promise => { const response = await this.esClient.ingest.putPipeline({ - id: id ?? KNOWLEDGE_BASE_INGEST_PIPELINE, + id: + id ?? + this.kbDataClient?.options.ingestPipelineResourceName ?? + KNOWLEDGE_BASE_INGEST_PIPELINE, description: description ?? 'Embedding pipeline for Elastic AI Assistant ELSER Knowledge Base', processors: [ @@ -381,7 +420,10 @@ export class ElasticsearchStore extends VectorStore { */ deletePipeline = async (pipelineId?: string): Promise => { const response = await this.esClient.ingest.deletePipeline({ - id: pipelineId ?? KNOWLEDGE_BASE_INGEST_PIPELINE, + id: + pipelineId ?? + this.kbDataClient?.options.ingestPipelineResourceName ?? + KNOWLEDGE_BASE_INGEST_PIPELINE, }); return response.acknowledged; @@ -395,12 +437,17 @@ export class ElasticsearchStore extends VectorStore { */ async isModelInstalled(modelId?: string): Promise { try { + // Code path for when `assistantKnowledgeBaseByDefault` FF is enabled + if (this.kbDataClient != null) { + // esStore.isModelInstalled() is actually checking if the model is deployed, not installed, so do that instead + return this.kbDataClient.isModelDeployed(); + } + const getResponse = await this.esClient.ml.getTrainedModelsStats({ model_id: modelId ?? this.model, }); this.logger.debug(`modelId: ${modelId}`); - this.logger.debug(`getResponse: ${JSON.stringify(getResponse, null, 2)}`); // For standardized way of checking deployment status see: https://github.com/elastic/elasticsearch/issues/106986 const isReadyESS = (stats: MlTrainedModelStats) => 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 7e7d5cf561d5e..e1e8cdc50eee0 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 @@ -14,18 +14,21 @@ import { initializeAgentExecutorWithOptions } from 'langchain/agents'; import { mockActionResponse } from '../../../__mocks__/action_result_data'; import { langChainMessages } from '../../../__mocks__/lang_chain_messages'; -import { ESQL_RESOURCE } from '../../../routes/knowledge_base/constants'; +import { KNOWLEDGE_BASE_INDEX_PATTERN } from '../../../routes/knowledge_base/constants'; import { callAgentExecutor } from '.'; import { PassThrough, Stream } from 'stream'; -import { - ActionsClientChatOpenAI, - ActionsClientLlm, -} from '@kbn/elastic-assistant-common/impl/language_models'; - -jest.mock('@kbn/elastic-assistant-common/impl/language_models', () => ({ - ActionsClientChatOpenAI: jest.fn(), - ActionsClientLlm: jest.fn(), -})); +import { ActionsClientChatOpenAI, ActionsClientSimpleChatModel } from '@kbn/langchain/server'; +import { AgentExecutorParams } from '../executors/types'; +import { ElasticsearchStore } from '../elasticsearch_store/elasticsearch_store'; + +jest.mock('@kbn/langchain/server', () => { + const original = jest.requireActual('@kbn/langchain/server'); + return { + ...original, + ActionsClientChatOpenAI: jest.fn(), + ActionsClientSimpleChatModel: jest.fn(), + }; +}); const mockConversationChain = { call: jest.fn(), @@ -85,20 +88,29 @@ const mockActions: ActionsPluginStart = {} as ActionsPluginStart; const mockLogger = loggerMock.create(); const mockTelemetry = coreMock.createSetup().analytics; const esClientMock = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; -const defaultProps = { +const esStoreMock = new ElasticsearchStore( + esClientMock, + KNOWLEDGE_BASE_INDEX_PATTERN, + mockLogger, + mockTelemetry +); +const defaultProps: AgentExecutorParams = { actions: mockActions, isEnabledKnowledgeBase: true, connectorId: mockConnectorId, esClient: esClientMock, + esStore: esStoreMock, llmType: 'openai', langChainMessages, logger: mockLogger, onNewReplacements: jest.fn(), request: mockRequest, - kbResource: ESQL_RESOURCE, - telemetry: mockTelemetry, replacements: {}, }; +const bedrockProps = { + ...defaultProps, + llmType: 'bedrock', +}; const executorMock = initializeAgentExecutorWithOptions as jest.Mock; describe('callAgentExecutor', () => { beforeEach(() => { @@ -132,140 +144,141 @@ describe('callAgentExecutor', () => { expect(mockCall.mock.calls[0][0].input).toEqual('What is my name?'); }); }); - describe('when the agent is not streaming', () => { - it('creates an instance of ActionsClientLlm with the expected context from the request', async () => { - await callAgentExecutor(defaultProps); - expect(ActionsClientLlm).toHaveBeenCalledWith({ - actions: mockActions, - connectorId: mockConnectorId, - logger: mockLogger, - maxRetries: 0, - request: mockRequest, - streaming: false, - temperature: 0.2, - llmType: 'openai', + describe('OpenAI', () => { + describe('when the agent is not streaming', () => { + it('creates an instance of ActionsClientChatOpenAI with the expected context from the request', async () => { + await callAgentExecutor(defaultProps); + + expect(ActionsClientChatOpenAI).toHaveBeenCalledWith({ + actions: mockActions, + connectorId: mockConnectorId, + logger: mockLogger, + maxRetries: 0, + request: mockRequest, + streaming: false, + temperature: 0.2, + llmType: 'openai', + }); }); - }); - it('uses the chat-conversational-react-description agent type', async () => { - await callAgentExecutor(defaultProps); + it('uses the openai-functions agent type', async () => { + await callAgentExecutor(defaultProps); + expect(mockCall.mock.calls[0][0].agentType).toEqual('openai-functions'); + }); - expect(mockCall.mock.calls[0][0].agentType).toEqual('chat-conversational-react-description'); - }); + it('returns the expected response', async () => { + const result = await callAgentExecutor(defaultProps); - it('uses the DynamicTool version of ESQLKnowledgeBaseTool', async () => { - await callAgentExecutor({ - ...defaultProps, - assistantTools: [ - { - name: 'ESQLKnowledgeBaseTool', - id: 'esql-knowledge-base-tool', - description: '', - sourceRegister: '', - isSupported: jest.fn(), - getTool: jest.fn().mockReturnValue(() => 'ESQLKnowledgeBaseTool'), + expect(result).toEqual({ + body: { + connector_id: 'mock-connector-id', + data: mockActionResponse, + status: 'ok', + replacements: {}, + trace_data: undefined, }, - { - name: 'ESQLKnowledgeBaseStructuredTool', - id: 'esql-knowledge-base-structured-tool', - description: '', - sourceRegister: '', - isSupported: jest.fn(), - getTool: jest.fn().mockReturnValue(() => 'ESQLKnowledgeBaseStructuredTool'), + headers: { + 'content-type': 'application/json', }, - { - name: 'UnrelatedTool', - id: 'unrelated-tool', - description: '', - sourceRegister: '', - isSupported: jest.fn(), - getTool: jest.fn().mockReturnValue(() => 'UnrelatedTool'), - }, - ], + }); }); - - expect(executorMock.mock.calls[0][0].length).toEqual(2); - expect(executorMock.mock.calls[0][0][0]()).toEqual('ESQLKnowledgeBaseTool'); }); + describe('when the agent is streaming', () => { + it('creates an instance of ActionsClientChatOpenAI with the expected context from the request', async () => { + await callAgentExecutor({ ...defaultProps, isStream: true }); + + expect(ActionsClientChatOpenAI).toHaveBeenCalledWith({ + actions: mockActions, + connectorId: mockConnectorId, + logger: mockLogger, + maxRetries: 0, + request: mockRequest, + streaming: true, + temperature: 0.2, + llmType: 'openai', + }); + }); - it('returns the expected response', async () => { - const result = await callAgentExecutor(defaultProps); - - expect(result).toEqual({ - body: { - connector_id: 'mock-connector-id', - data: mockActionResponse, - status: 'ok', - replacements: {}, - trace_data: undefined, - }, - headers: { - 'content-type': 'application/json', - }, + it('uses the openai-functions agent type', async () => { + await callAgentExecutor({ ...defaultProps, isStream: true }); + expect(mockInvoke.mock.calls[0][0].agentType).toEqual('openai-functions'); }); }); }); - describe('when the agent is streaming', () => { - it('creates an instance of ActionsClientChatOpenAI with the expected context from the request', async () => { - await callAgentExecutor({ ...defaultProps, isStream: true }); - - expect(ActionsClientChatOpenAI).toHaveBeenCalledWith({ - actions: mockActions, - connectorId: mockConnectorId, - logger: mockLogger, - maxRetries: 0, - request: mockRequest, - streaming: true, - temperature: 0.2, - llmType: 'openai', + + describe('Bedrock', () => { + describe('when the agent is not streaming', () => { + it('creates an instance of ActionsClientSimpleChatModel with the expected context from the request', async () => { + await callAgentExecutor(bedrockProps); + + expect(ActionsClientSimpleChatModel).toHaveBeenCalledWith({ + actions: mockActions, + connectorId: mockConnectorId, + logger: mockLogger, + maxRetries: 0, + request: mockRequest, + streaming: false, + temperature: 0, + llmType: 'bedrock', + }); }); - }); - it('uses the openai-functions agent type', async () => { - await callAgentExecutor({ ...defaultProps, isStream: true }); + it('uses the structured-chat-zero-shot-react-description agent type', async () => { + await callAgentExecutor(bedrockProps); + expect(mockCall.mock.calls[0][0].agentType).toEqual( + 'structured-chat-zero-shot-react-description' + ); + }); - expect(mockInvoke.mock.calls[0][0].agentType).toEqual('openai-functions'); - }); + it('returns the expected response', async () => { + const result = await callAgentExecutor(bedrockProps); - it('uses the DynamicStructuredTool version of ESQLKnowledgeBaseTool', async () => { - await callAgentExecutor({ - ...defaultProps, - isStream: true, - assistantTools: [ - { - name: 'ESQLKnowledgeBaseTool', - id: 'esql-knowledge-base-tool', - description: '', - sourceRegister: '', - isSupported: jest.fn(), - getTool: jest.fn().mockReturnValue(() => 'ESQLKnowledgeBaseTool'), + expect(result).toEqual({ + body: { + connector_id: 'mock-connector-id', + data: mockActionResponse, + status: 'ok', + replacements: {}, + trace_data: undefined, }, - { - name: 'ESQLKnowledgeBaseStructuredTool', - id: 'esql-knowledge-base-structured-tool', - description: '', - sourceRegister: '', - isSupported: jest.fn(), - getTool: jest.fn().mockReturnValue(() => 'ESQLKnowledgeBaseStructuredTool'), + headers: { + 'content-type': 'application/json', }, - { - name: 'UnrelatedTool', - id: 'unrelated-tool', - description: '', - sourceRegister: '', - isSupported: jest.fn(), - getTool: jest.fn().mockReturnValue(() => 'UnrelatedTool'), - }, - ], + }); + }); + }); + describe('when the agent is streaming', () => { + it('creates an instance of ActionsClientSimpleChatModel with the expected context from the request', async () => { + await callAgentExecutor({ ...bedrockProps, isStream: true }); + + expect(ActionsClientSimpleChatModel).toHaveBeenCalledWith({ + actions: mockActions, + connectorId: mockConnectorId, + logger: mockLogger, + maxRetries: 0, + request: mockRequest, + streaming: true, + temperature: 0, + llmType: 'bedrock', + }); }); - expect(executorMock.mock.calls[0][0].length).toEqual(2); - expect(executorMock.mock.calls[0][0][0]()).toEqual('ESQLKnowledgeBaseStructuredTool'); + it('uses the structured-chat-zero-shot-react-description agent type', async () => { + await callAgentExecutor({ ...bedrockProps, isStream: true }); + expect(mockInvoke.mock.calls[0][0].agentType).toEqual( + 'structured-chat-zero-shot-react-description' + ); + }); }); + }); + describe.each([ + ['OpenAI', defaultProps], + ['Bedrock', bedrockProps], + ])('Common streaming tests - %s', (_, theProps) => { it('returns the expected response', async () => { - const result = await callAgentExecutor({ ...defaultProps, isStream: true }); + const result = await callAgentExecutor({ ...theProps, isStream: true }); expect(result.body).toBeInstanceOf(Stream.PassThrough); expect(result.headers).toEqual({ 'Cache-Control': 'no-cache', @@ -292,7 +305,7 @@ describe('callAgentExecutor', () => { }) ); const onLlmResponse = jest.fn(async () => {}); // We need it to be a promise, or it'll crash because of missing `.catch` - await callAgentExecutor({ ...defaultProps, onLlmResponse, isStream: true }); + await callAgentExecutor({ ...theProps, onLlmResponse, isStream: true }); expect(onLlmResponse).toHaveBeenCalledWith( 'hello', @@ -321,7 +334,7 @@ describe('callAgentExecutor', () => { }) ); const onLlmResponse = jest.fn(async () => {}); // We need it to be a promise, or it'll crash because of missing `.catch` - await callAgentExecutor({ ...defaultProps, onLlmResponse, isStream: true }); + await callAgentExecutor({ ...theProps, onLlmResponse, isStream: true }); expect(mockPush).toHaveBeenCalledWith({ payload: 'hi', type: 'content' }); expect(mockPush).not.toHaveBeenCalledWith({ payload: 'hey', type: 'content' }); @@ -346,7 +359,7 @@ describe('callAgentExecutor', () => { }) ); const onLlmResponse = jest.fn(); - await callAgentExecutor({ ...defaultProps, onLlmResponse, isStream: true }); + await callAgentExecutor({ ...theProps, onLlmResponse, isStream: true }); expect(mockPush).toHaveBeenCalledWith({ payload: 'hi', type: 'content' }); expect(mockPush).toHaveBeenCalledWith({ payload: 'hey', type: 'content' }); 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 f8e2f2426bf89..8323712c50aa7 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 @@ -13,20 +13,18 @@ import { streamFactory } from '@kbn/ml-response-stream/server'; import { transformError } from '@kbn/securitysolution-es-utils'; import { RetrievalQAChain } from 'langchain/chains'; import { + getDefaultArguments, ActionsClientChatOpenAI, - ActionsClientLlm, -} from '@kbn/elastic-assistant-common/impl/language_models'; -import { getDefaultArguments } from '@kbn/elastic-assistant-common/impl/language_models/constants'; -import { ElasticsearchStore } from '../elasticsearch_store/elasticsearch_store'; -import { KNOWLEDGE_BASE_INDEX_PATTERN } from '../../../routes/knowledge_base/constants'; + ActionsClientSimpleChatModel, +} from '@kbn/langchain/server'; import { AgentExecutor } from '../executors/types'; -import { withAssistantSpan } from '../tracers/with_assistant_span'; import { APMTracer } from '../tracers/apm_tracer'; import { AssistantToolParams } from '../../../types'; +import { withAssistantSpan } from '../tracers/with_assistant_span'; export const DEFAULT_AGENT_EXECUTOR_ID = 'Elastic AI Assistant Agent Executor'; /** - * The default agent executor used by the Elastic AI Assistant. Main agent/chain that wraps the ActionsClientLlm, + * The default agent executor used by the Elastic AI Assistant. Main agent/chain that wraps the ActionsClientSimpleChatModel, * sets up a conversation BufferMemory from chat history, and registers tools like the ESQLKnowledgeBaseTool. * */ @@ -38,9 +36,8 @@ export const callAgentExecutor: AgentExecutor = async ({ isEnabledKnowledgeBase, assistantTools = [], connectorId, - elserId, esClient, - kbResource, + esStore, langChainMessages, llmType, logger, @@ -50,12 +47,10 @@ export const callAgentExecutor: AgentExecutor = async ({ replacements, request, size, - telemetry, traceOptions, }) => { - // TODO implement llmClass for bedrock streaming - // tracked here: https://github.com/elastic/security-team/issues/7363 - const llmClass = isStream ? ActionsClientChatOpenAI : ActionsClientLlm; + const isOpenAI = llmType === 'openai'; + const llmClass = isOpenAI ? ActionsClientChatOpenAI : ActionsClientSimpleChatModel; const llm = new llmClass({ actions, @@ -87,16 +82,6 @@ export const callAgentExecutor: AgentExecutor = async ({ returnMessages: true, }); - // ELSER backed ElasticsearchStore for Knowledge Base - const esStore = new ElasticsearchStore( - esClient, - KNOWLEDGE_BASE_INDEX_PATTERN, - logger, - telemetry, - elserId, - kbResource - ); - const modelExists = await esStore.isModelInstalled(); // Create a chain that uses the ELSER backed ElasticsearchStore, override k=10 for esql query generation for now @@ -117,13 +102,9 @@ export const callAgentExecutor: AgentExecutor = async ({ size, }; - const tools: ToolInterface[] = assistantTools - .filter((tool) => - isStream - ? tool.id !== 'esql-knowledge-base-tool' - : tool.id !== 'esql-knowledge-base-structured-tool' - ) - .flatMap((tool) => tool.getTool(assistantToolParams) ?? []); + const tools: ToolInterface[] = assistantTools.flatMap( + (tool) => tool.getTool(assistantToolParams) ?? [] + ); logger.debug(`applicable tools: ${JSON.stringify(tools.map((t) => t.name).join(', '), null, 2)}`); @@ -132,15 +113,20 @@ export const callAgentExecutor: AgentExecutor = async ({ verbose: false, handleParsingErrors: 'Try again, paying close attention to the allowed tool input', }; - // isStream check is not on agentType alone because typescript doesn't like - const executor = isStream + // isOpenAI check is not on agentType alone because typescript doesn't like + const executor = isOpenAI ? await initializeAgentExecutorWithOptions(tools, llm, { agentType: 'openai-functions', ...executorArgs, }) : await initializeAgentExecutorWithOptions(tools, llm, { - agentType: 'chat-conversational-react-description', + agentType: 'structured-chat-zero-shot-react-description', ...executorArgs, + returnIntermediateSteps: false, + agentArgs: { + // this is important to help LangChain correctly format tool input + humanMessageTemplate: `Question: {input}\n\n{agent_scratchpad}`, + }, }); // Sets up tracer for tracing executions to APM. See x-pack/plugins/elastic_assistant/server/lib/langchain/tracers/README.mdx diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/executors/openai_functions_executor.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/executors/openai_functions_executor.ts index 2b3d07708e2e1..62b1d7ac7814f 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/executors/openai_functions_executor.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/executors/openai_functions_executor.ts @@ -10,9 +10,7 @@ import { RetrievalQAChain } from 'langchain/chains'; import { BufferMemory, ChatMessageHistory } from 'langchain/memory'; import { ChainTool } from 'langchain/tools/chain'; -import { ActionsClientLlm } from '@kbn/elastic-assistant-common/impl/language_models'; -import { ElasticsearchStore } from '../elasticsearch_store/elasticsearch_store'; -import { KNOWLEDGE_BASE_INDEX_PATTERN } from '../../../routes/knowledge_base/constants'; +import { ActionsClientLlm } from '@kbn/langchain/server'; import { AgentExecutor } from './types'; import { withAssistantSpan } from '../tracers/with_assistant_span'; import { APMTracer } from '../tracers/apm_tracer'; @@ -30,13 +28,11 @@ export const callOpenAIFunctionsExecutor: AgentExecutor = async ({ actions, connectorId, esClient, + esStore, langChainMessages, llmType, logger, request, - elserId, - kbResource, - telemetry, traceOptions, }) => { const llm = new ActionsClientLlm({ @@ -59,16 +55,6 @@ export const callOpenAIFunctionsExecutor: AgentExecutor = async ({ returnMessages: true, }); - // ELSER backed ElasticsearchStore for Knowledge Base - const esStore = new ElasticsearchStore( - esClient, - KNOWLEDGE_BASE_INDEX_PATTERN, - logger, - telemetry, - elserId, - kbResource - ); - const modelExists = await esStore.isModelInstalled(); if (!modelExists) { throw new Error( 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 ce2833fa14480..8acd7f4fcdde2 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 @@ -11,12 +11,12 @@ import { BaseMessage } from '@langchain/core/messages'; import { Logger } from '@kbn/logging'; import { KibanaRequest, ResponseHeaders } from '@kbn/core-http-server'; import type { LangChainTracer } from '@langchain/core/tracers/tracer_langchain'; -import type { AnalyticsServiceSetup } from '@kbn/core-analytics-server'; import { ExecuteConnectorRequestBody, Message, Replacements } from '@kbn/elastic-assistant-common'; import { StreamResponseWithHeaders } from '@kbn/ml-response-stream/server'; import { AnonymizationFieldResponse } from '@kbn/elastic-assistant-common/impl/schemas/anonymization_fields/bulk_crud_anonymization_fields_route.gen'; import { ResponseBody } from '../types'; import type { AssistantTool } from '../../../types'; +import { ElasticsearchStore } from '../elasticsearch_store/elasticsearch_store'; export interface AgentExecutorParams { abortSignal?: AbortSignal; @@ -27,7 +27,7 @@ export interface AgentExecutorParams { assistantTools?: AssistantTool[]; connectorId: string; esClient: ElasticsearchClient; - kbResource: string | undefined; + esStore: ElasticsearchStore; langChainMessages: BaseMessage[]; llmType?: string; logger: Logger; @@ -41,9 +41,7 @@ export interface AgentExecutorParams { ) => Promise; request: KibanaRequest; size?: number; - elserId?: string; traceOptions?: TraceOptions; - telemetry: AnalyticsServiceSetup; } export interface StaticReturnType { diff --git a/x-pack/plugins/elastic_assistant/server/lib/parse_stream.ts b/x-pack/plugins/elastic_assistant/server/lib/parse_stream.ts index 057a0f9247506..e42ce6e3651fb 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/parse_stream.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/parse_stream.ts @@ -6,14 +6,14 @@ */ import { Readable } from 'stream'; -import { finished } from 'stream/promises'; -import { handleBedrockChunk } from '@kbn/elastic-assistant-common'; import { Logger } from '@kbn/core/server'; +import { parseBedrockStream } from '@kbn/langchain/server'; type StreamParser = ( responseStream: Readable, logger: Logger, - abortSignal?: AbortSignal + abortSignal?: AbortSignal, + tokenHandler?: (token: string) => void ) => Promise; export const handleStreamStorage = async ({ @@ -87,47 +87,3 @@ const parseOpenAIResponse = (responseBody: string) => const msg = line.choices[0].delta; return prev + (msg.content || ''); }, ''); - -const parseBedrockStream: StreamParser = async (responseStream, logger, abortSignal) => { - const responseBuffer: Uint8Array[] = []; - if (abortSignal) { - abortSignal.addEventListener('abort', () => { - responseStream.destroy(new Error('Aborted')); - return parseBedrockBuffer(responseBuffer, logger); - }); - } - responseStream.on('data', (chunk) => { - // special encoding for bedrock, do not attempt to convert to string - responseBuffer.push(chunk); - }); - - await finished(responseStream).catch((err) => { - if (abortSignal?.aborted) { - logger.info('Bedrock stream parsing was aborted.'); - } else { - throw err; - } - }); - - return parseBedrockBuffer(responseBuffer, logger); -}; - -/** - * Parses a Bedrock buffer from an array of chunks. - * - * @param {Uint8Array[]} chunks - Array of Uint8Array chunks to be parsed. - * @returns {string} - Parsed string from the Bedrock buffer. - */ -const parseBedrockBuffer = (chunks: Uint8Array[], logger: Logger): string => { - // Initialize an empty Uint8Array to store the concatenated buffer. - let bedrockBuffer: Uint8Array = new Uint8Array(0); - - // Map through each chunk to process the Bedrock buffer. - return chunks - .map((chunk) => { - const processedChunk = handleBedrockChunk({ chunk, bedrockBuffer, logger }); - bedrockBuffer = processedChunk.bedrockBuffer; - return processedChunk.decodedChunk; - }) - .join(''); -}; diff --git a/x-pack/plugins/elastic_assistant/server/plugin.ts b/x-pack/plugins/elastic_assistant/server/plugin.ts index 53b05857beb4b..7a092928ce99a 100755 --- a/x-pack/plugins/elastic_assistant/server/plugin.ts +++ b/x-pack/plugins/elastic_assistant/server/plugin.ts @@ -24,6 +24,7 @@ import { RequestContextFactory } from './routes/request_context_factory'; import { PLUGIN_ID } from '../common/constants'; import { registerRoutes } from './routes/register_routes'; import { appContextService } from './services/app_context'; +import { createGetElserId } from './ai_assistant_service/helpers'; export class ElasticAssistantPlugin implements @@ -53,6 +54,7 @@ export class ElasticAssistantPlugin this.assistantService = new AIAssistantService({ logger: this.logger.get('service'), + ml: plugins.ml, taskManager: plugins.taskManager, kibanaVersion: this.kibanaVersion, elasticsearchClientPromise: core @@ -76,8 +78,8 @@ export class ElasticAssistantPlugin ); events.forEach((eventConfig) => core.analytics.registerEventType(eventConfig)); - // this.assistantService registerKBTask - registerRoutes(router, this.logger, plugins); + const getElserId = createGetElserId(plugins.ml); + registerRoutes(router, this.logger, getElserId); return { actions: plugins.actions, getRegisteredFeatures: (pluginName: string) => { diff --git a/x-pack/plugins/elastic_assistant/server/routes/anonymization_fields/bulk_actions_route.ts b/x-pack/plugins/elastic_assistant/server/routes/anonymization_fields/bulk_actions_route.ts index 94788d2d1d926..47213cb0d278e 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/anonymization_fields/bulk_actions_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/anonymization_fields/bulk_actions_route.ts @@ -118,7 +118,7 @@ export const bulkActionAnonymizationFieldsRoute = ( ) => { router.versioned .post({ - access: 'public', + access: 'internal', path: ELASTIC_AI_ASSISTANT_ANONYMIZATION_FIELDS_URL_BULK_ACTION, options: { tags: ['access:securitySolution-updateAIAssistantAnonymization'], @@ -129,7 +129,7 @@ export const bulkActionAnonymizationFieldsRoute = ( }) .addVersion( { - version: API_VERSIONS.public.v1, + version: API_VERSIONS.internal.v1, validate: { request: { body: buildRouteValidationWithZod(PerformBulkActionRequestBody), diff --git a/x-pack/plugins/elastic_assistant/server/routes/anonymization_fields/find_route.ts b/x-pack/plugins/elastic_assistant/server/routes/anonymization_fields/find_route.ts index 904a80d6a3ea4..c0383b1b3b38c 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/anonymization_fields/find_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/anonymization_fields/find_route.ts @@ -30,7 +30,7 @@ export const findAnonymizationFieldsRoute = ( ) => { router.versioned .get({ - access: 'public', + access: 'internal', path: ELASTIC_AI_ASSISTANT_ANONYMIZATION_FIELDS_URL_FIND, options: { tags: ['access:elasticAssistant'], @@ -38,7 +38,7 @@ export const findAnonymizationFieldsRoute = ( }) .addVersion( { - version: API_VERSIONS.public.v1, + version: API_VERSIONS.internal.v1, validate: { request: { query: buildRouteValidationWithZod(FindAnonymizationFieldsRequestQuery), diff --git a/x-pack/plugins/elastic_assistant/server/routes/attack_discovery/helpers.ts b/x-pack/plugins/elastic_assistant/server/routes/attack_discovery/helpers.ts index c473c21da6e84..65a3c96b27a0c 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/attack_discovery/helpers.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/attack_discovery/helpers.ts @@ -12,9 +12,9 @@ import { ExecuteConnectorRequestBody, Replacements, } from '@kbn/elastic-assistant-common'; -import { ActionsClientLlm } from '@kbn/elastic-assistant-common/impl/language_models'; import { AnonymizationFieldResponse } from '@kbn/elastic-assistant-common/impl/schemas/anonymization_fields/bulk_crud_anonymization_fields_route.gen'; import { v4 as uuidv4 } from 'uuid'; +import { ActionsClientLlm } from '@kbn/langchain/server'; import { AssistantToolParams } from '../../types'; diff --git a/x-pack/plugins/elastic_assistant/server/routes/attack_discovery/post_attack_discovery.ts b/x-pack/plugins/elastic_assistant/server/routes/attack_discovery/post_attack_discovery.ts index 923f33dc44f3d..5d9240dd1d97d 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/attack_discovery/post_attack_discovery.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/attack_discovery/post_attack_discovery.ts @@ -6,7 +6,6 @@ */ import { buildRouteValidationWithZod } from '@kbn/elastic-assistant-common/impl/schemas/common'; -import { ActionsClientLlm } from '@kbn/elastic-assistant-common/impl/language_models'; import { type IKibanaResponse, IRouter, Logger } from '@kbn/core/server'; import { AttackDiscoveryPostRequestBody, @@ -15,6 +14,7 @@ import { Replacements, } from '@kbn/elastic-assistant-common'; import { transformError } from '@kbn/securitysolution-es-utils'; +import { ActionsClientLlm } from '@kbn/langchain/server'; import { ATTACK_DISCOVERY } from '../../../common/constants'; import { getAssistantToolParams } from './helpers'; diff --git a/x-pack/plugins/elastic_assistant/server/routes/evaluate/post_evaluate.test.ts b/x-pack/plugins/elastic_assistant/server/routes/evaluate/post_evaluate.test.ts index 0555b313f27f9..b3fb27fa835c1 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/evaluate/post_evaluate.test.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/evaluate/post_evaluate.test.ts @@ -9,7 +9,8 @@ import { postEvaluateRoute } from './post_evaluate'; import { serverMock } from '../../__mocks__/server'; import { requestContextMock } from '../../__mocks__/request_context'; import { getPostEvaluateRequest } from '../../__mocks__/request'; -import type { +import { + defaultAssistantFeatures, PostEvaluateRequestBodyInput, PostEvaluateRequestQueryInput, } from '@kbn/elastic-assistant-common'; @@ -45,6 +46,7 @@ describe('Post Evaluate Route', () => { describe('Capabilities', () => { it('returns a 404 if evaluate feature is not registered', async () => { context.elasticAssistant.getRegisteredFeatures.mockReturnValueOnce({ + ...defaultAssistantFeatures, assistantModelEvaluation: false, }); 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 d1bf9dfa26ab1..ef1950b5e90ad 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 @@ -17,9 +17,9 @@ import { PostEvaluateResponse, ExecuteConnectorRequestBody, } from '@kbn/elastic-assistant-common'; -import { ActionsClientLlm } from '@kbn/elastic-assistant-common/impl/language_models'; +import { ActionsClientLlm } from '@kbn/langchain/server'; import { buildRouteValidationWithZod } from '@kbn/elastic-assistant-common/impl/schemas/common'; -import { ESQL_RESOURCE } from '../knowledge_base/constants'; +import { ESQL_RESOURCE, KNOWLEDGE_BASE_INDEX_PATTERN } from '../knowledge_base/constants'; import { buildResponse } from '../../lib/build_response'; import { ElasticAssistantRequestHandlerContext, GetElser } from '../../types'; import { EVALUATE } from '../../../common/constants'; @@ -37,6 +37,7 @@ import { DEFAULT_PLUGIN_NAME, getPluginNameFromRequest } from '../helpers'; * and reference your specific AgentExecutor function */ import { AGENT_EXECUTOR_MAP } from '../../lib/langchain/executors'; +import { ElasticsearchStore } from '../../lib/langchain/elasticsearch_store/elasticsearch_store'; const DEFAULT_SIZE = 20; @@ -136,7 +137,7 @@ export const postEvaluateRoute = ( const esClient = (await context.core).elasticsearch.client.asCurrentUser; // Default ELSER model - const elserId = await getElser(request, (await context.core).savedObjects.getClient()); + const elserId = await getElser(); // Skeleton request from route to pass to the agents // params will be passed to the actions executor @@ -157,6 +158,27 @@ export const postEvaluateRoute = ( }, }; + // Create an ElasticsearchStore for KB interactions + // Setup with kbDataClient if `enableKnowledgeBaseByDefault` 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 esStore = new ElasticsearchStore( + esClient, + kbIndex, + logger, + telemetry, + elserId, + ESQL_RESOURCE, + kbDataClient + ); + // Create an array of executor functions to call in batches // One for each connector/model + agent combination // Hoist `langChainMessages` so they can be batched by dataset.input in the evaluator @@ -175,14 +197,12 @@ export const postEvaluateRoute = ( assistantTools, connectorId, esClient, - elserId, + esStore, isStream: false, langChainMessages, llmType: 'openai', logger, request: skeletonRequest, - kbResource: ESQL_RESOURCE, - telemetry, traceOptions: { exampleId, projectName, 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 index 0443bd1b3eedd..ad130cddc5560 100644 --- 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 @@ -36,7 +36,7 @@ describe('Delete Knowledge Base Route', () => { }); test('returns 500 if error is thrown when deleting resources', async () => { - context.core.elasticsearch.client.asCurrentUser.indices.delete.mockRejectedValue( + context.core.elasticsearch.client.asInternalUser.indices.delete.mockRejectedValue( new Error('Test error') ); const response = await server.inject( 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 6886b56f7ef32..6e81738a7376f 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 @@ -8,7 +8,10 @@ import { IRouter, KibanaRequest } from '@kbn/core/server'; import { transformError } from '@kbn/securitysolution-es-utils'; -import { ELASTIC_AI_ASSISTANT_INTERNAL_API_VERSION } from '@kbn/elastic-assistant-common'; +import { + ELASTIC_AI_ASSISTANT_INTERNAL_API_VERSION, + ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_URL, +} from '@kbn/elastic-assistant-common'; import { DeleteKnowledgeBaseRequestParams, DeleteKnowledgeBaseResponse, @@ -16,9 +19,10 @@ import { import { buildRouteValidationWithZod } from '@kbn/elastic-assistant-common/impl/schemas/common'; import { buildResponse } from '../../lib/build_response'; import { ElasticAssistantRequestHandlerContext } from '../../types'; -import { KNOWLEDGE_BASE } from '../../../common/constants'; 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 { getKbResource } from './get_kb_resource'; /** * Delete Knowledge Base index, pipeline, and resources (collection of documents) @@ -30,11 +34,9 @@ export const deleteKnowledgeBaseRoute = ( router.versioned .delete({ access: 'internal', - path: KNOWLEDGE_BASE, + path: ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_URL, options: { - // Note: Relying on current user privileges to scope an esClient. - // Add `access:kbnElasticAssistant` to limit API access to only users with assistant privileges - tags: [], + tags: ['access:elasticAssistant'], }, }) .addVersion( @@ -51,22 +53,43 @@ 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 = - request.params.resource != null - ? decodeURIComponent(request.params.resource) - : undefined; + const kbResource = getKbResource(request); - // Get a scoped esClient for deleting the Knowledge Base index, pipeline, and documents - const esClient = (await context.core).elasticsearch.client.asCurrentUser; - const esStore = new ElasticsearchStore( + const esClient = (await context.core).elasticsearch.client.asInternalUser; + let esStore = new ElasticsearchStore( esClient, KNOWLEDGE_BASE_INDEX_PATTERN, logger, telemetry ); + // 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/create_route.ts b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/create_route.ts new file mode 100644 index 0000000000000..0c31974a20785 --- /dev/null +++ b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/create_route.ts @@ -0,0 +1,76 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { IKibanaResponse } from '@kbn/core/server'; +import { transformError } from '@kbn/securitysolution-es-utils'; +import { + API_VERSIONS, + ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_ENTRIES_URL, +} from '@kbn/elastic-assistant-common'; +import { buildRouteValidationWithZod } from '@kbn/elastic-assistant-common/impl/schemas/common'; +import { + KnowledgeBaseEntryCreateProps, + KnowledgeBaseEntryResponse, +} from '@kbn/elastic-assistant-common/impl/schemas/knowledge_base/common_attributes.gen'; +import { ElasticAssistantPluginRouter } from '../../../types'; +import { buildResponse } from '../../utils'; +import { UPGRADE_LICENSE_MESSAGE, hasAIAssistantLicense } from '../../helpers'; + +export const createKnowledgeBaseEntryRoute = (router: ElasticAssistantPluginRouter): void => { + router.versioned + .post({ + access: 'public', + path: ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_ENTRIES_URL, + + options: { + tags: ['access:elasticAssistant'], + }, + }) + .addVersion( + { + version: API_VERSIONS.public.v1, + validate: { + request: { + body: buildRouteValidationWithZod(KnowledgeBaseEntryCreateProps), + }, + }, + }, + async (context, request, response): Promise> => { + const assistantResponse = buildResponse(response); + try { + const ctx = await context.resolve(['core', 'elasticAssistant', 'licensing']); + const license = ctx.licensing.license; + if (!hasAIAssistantLicense(license)) { + return response.forbidden({ + body: { + message: UPGRADE_LICENSE_MESSAGE, + }, + }); + } + + const authenticatedUser = ctx.elasticAssistant.getCurrentUser(); + if (authenticatedUser == null) { + return assistantResponse.error({ + body: `Authenticated user not found`, + statusCode: 401, + }); + } + + return assistantResponse.error({ + body: `knowledge base entry was not created`, + statusCode: 400, + }); + } catch (err) { + const error = transformError(err as Error); + return assistantResponse.error({ + body: error.message, + statusCode: error.statusCode, + }); + } + } + ); +}; 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 f37f2a3ab2882..ba8992d9c19bd 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 @@ -10,6 +10,7 @@ import { serverMock } from '../../__mocks__/server'; import { requestContextMock } from '../../__mocks__/request_context'; import { getGetKnowledgeBaseStatusRequest } from '../../__mocks__/request'; import { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks'; +import { AuthenticatedUser } from '@kbn/core-security-common'; describe('Get Knowledge Base Status Route', () => { let server: ReturnType; @@ -19,10 +20,18 @@ describe('Get Knowledge Base Status Route', () => { clients.core.elasticsearch.client = elasticsearchServiceMock.createScopedClusterClient(); const mockGetElser = jest.fn().mockResolvedValue('.elser_model_2'); + const mockUser = { + username: 'my_username', + authentication_realm: { + type: 'my_realm_type', + name: 'my_realm_name', + }, + } as AuthenticatedUser; beforeEach(() => { server = serverMock.create(); ({ context } = requestContextMock.createTools()); + context.elasticAssistant.getCurrentUser.mockReturnValue(mockUser); getKnowledgeBaseStatusRoute(server.router, mockGetElser); }); @@ -37,7 +46,7 @@ describe('Get Knowledge Base Status Route', () => { }); test('returns 500 if error is thrown in checking kb status', async () => { - context.core.elasticsearch.client.asCurrentUser.indices.exists.mockRejectedValue( + context.core.elasticsearch.client.asInternalUser.indices.exists.mockRejectedValue( new Error('Test error') ); const response = await server.inject( 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 c7d83e8c24401..a8d2e96227d60 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 @@ -9,6 +9,7 @@ import { transformError } from '@kbn/securitysolution-es-utils'; import { ELASTIC_AI_ASSISTANT_INTERNAL_API_VERSION, + ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_URL, ReadKnowledgeBaseRequestParams, ReadKnowledgeBaseResponse, } from '@kbn/elastic-assistant-common'; @@ -17,9 +18,9 @@ import { KibanaRequest } from '@kbn/core/server'; import { getKbResource } from './get_kb_resource'; import { buildResponse } from '../../lib/build_response'; import { ElasticAssistantPluginRouter, GetElser } from '../../types'; -import { KNOWLEDGE_BASE } from '../../../common/constants'; 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'; /** * Get the status of the Knowledge Base index, pipeline, and resources (collection of documents) @@ -34,11 +35,9 @@ export const getKnowledgeBaseStatusRoute = ( router.versioned .get({ access: 'internal', - path: KNOWLEDGE_BASE, + path: ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_URL, options: { - // Note: Relying on current user privileges to scope an esClient. - // Add `access:kbnElasticAssistant` to limit API access to only users with assistant privileges - tags: [], + tags: ['access:elasticAssistant'], }, }) .addVersion( @@ -57,11 +56,10 @@ export const getKnowledgeBaseStatusRoute = ( const telemetry = assistantContext.telemetry; try { - // Get a scoped esClient for finding the status of the Knowledge Base index, pipeline, and documents - const esClient = (await context.core).elasticsearch.client.asCurrentUser; - const elserId = await getElser(request, (await context.core).savedObjects.getClient()); + const esClient = (await context.core).elasticsearch.client.asInternalUser; + const elserId = await getElser(); const kbResource = getKbResource(request); - const esStore = new ElasticsearchStore( + let esStore = new ElasticsearchStore( esClient, KNOWLEDGE_BASE_INDEX_PATTERN, logger, @@ -70,6 +68,37 @@ export const getKnowledgeBaseStatusRoute = ( kbResource ); + 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); @@ -77,6 +106,7 @@ export const getKnowledgeBaseStatusRoute = ( const body: ReadKnowledgeBaseResponse = { elser_exists: modelExists, index_exists: indexExists, + is_setup_in_progress: 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 ceb5f1b3879f6..547923b5c0d17 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 @@ -10,6 +10,7 @@ import { serverMock } from '../../__mocks__/server'; import { requestContextMock } from '../../__mocks__/request_context'; import { getPostKnowledgeBaseRequest } from '../../__mocks__/request'; import { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks'; +import { AuthenticatedUser } from '@kbn/core-security-common'; describe('Post Knowledge Base Route', () => { let server: ReturnType; @@ -19,10 +20,18 @@ describe('Post Knowledge Base Route', () => { clients.core.elasticsearch.client = elasticsearchServiceMock.createScopedClusterClient(); const mockGetElser = jest.fn().mockResolvedValue('.elser_model_2'); + const mockUser = { + username: 'my_username', + authentication_realm: { + type: 'my_realm_type', + name: 'my_realm_name', + }, + } as AuthenticatedUser; beforeEach(() => { server = serverMock.create(); ({ context } = requestContextMock.createTools()); + context.elasticAssistant.getCurrentUser.mockReturnValue(mockUser); postKnowledgeBaseRoute(server.router, mockGetElser); }); @@ -38,7 +47,7 @@ describe('Post Knowledge Base Route', () => { }); test('returns 500 if error is thrown when creating resources', async () => { - context.core.elasticsearch.client.asCurrentUser.indices.exists.mockRejectedValue( + context.core.elasticsearch.client.asInternalUser.indices.exists.mockRejectedValue( new Error('Test error') ); const response = await server.inject( 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 17c2011fbc0f5..bc511d99eb63d 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 @@ -11,20 +11,26 @@ import { ELASTIC_AI_ASSISTANT_INTERNAL_API_VERSION, CreateKnowledgeBaseRequestParams, CreateKnowledgeBaseResponse, + ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_URL, } from '@kbn/elastic-assistant-common'; import { buildRouteValidationWithZod } from '@kbn/elastic-assistant-common/impl/schemas/common'; import { IKibanaResponse, KibanaRequest } from '@kbn/core/server'; import { buildResponse } from '../../lib/build_response'; import { ElasticAssistantPluginRouter, GetElser } from '../../types'; -import { KNOWLEDGE_BASE } from '../../../common/constants'; 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 +const ROUTE_HANDLER_TIMEOUT = 10 * 60 * 1000; // 10 * 60 seconds = 10 minutes /** * Load Knowledge Base index, pipeline, and resources (collection of documents) * @param router + * @param getElser */ export const postKnowledgeBaseRoute = ( router: ElasticAssistantPluginRouter, @@ -33,11 +39,12 @@ export const postKnowledgeBaseRoute = ( router.versioned .post({ access: 'internal', - path: KNOWLEDGE_BASE, + path: ELASTIC_AI_ASSISTANT_KNOWLEDGE_BASE_URL, options: { - // Note: Relying on current user privileges to scope an esClient. - // Add `access:kbnElasticAssistant` to limit API access to only users with assistant privileges - tags: [], + tags: ['access:elasticAssistant'], + timeout: { + idleSocket: ROUTE_HANDLER_TIMEOUT, + }, }, }) .addVersion( @@ -58,12 +65,44 @@ export const postKnowledgeBaseRoute = ( const assistantContext = await context.elasticAssistant; const logger = assistantContext.logger; const telemetry = assistantContext.telemetry; + const elserId = await getElser(); + const core = await context.core; + 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 { - const core = await context.core; - // Get a scoped esClient for creating the Knowledge Base index, pipeline, and documents - const esClient = core.elasticsearch.client.asCurrentUser; - const elserId = await getElser(request, core.savedObjects.getClient()); + // 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 kbResource = getKbResource(request); const esStore = new ElasticsearchStore( esClient, 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 6c2be6b8c7120..5ee8d8e83c846 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 @@ -23,6 +23,7 @@ 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'; const actionsClient = actionsClientMock.create(); jest.mock('../lib/build_response', () => ({ @@ -92,6 +93,7 @@ const mockContext = { getActionsClientWithRequest: jest.fn().mockResolvedValue(actionsClient), }, getRegisteredTools: jest.fn(() => []), + getRegisteredFeatures: jest.fn(() => defaultAssistantFeatures), logger: loggingSystemMock.createLogger(), telemetry: { ...coreMock.createSetup().analytics, reportEvent }, getCurrentUser: () => ({ @@ -652,11 +654,84 @@ describe('postActionsConnectorExecuteRoute', () => { ); expect(result).toEqual({ - body: { - connector_id: 'mock-connector-id', - data: mockActionResponse, - status: 'ok', + body: mockStream, + headers: { + 'Cache-Control': 'no-cache', + Connection: 'keep-alive', + 'Transfer-Encoding': 'chunked', + 'X-Accel-Buffering': 'no', + 'X-Content-Type-Options': 'nosniff', + }, + }); + }), + }; + }), + }, + }; + await postActionsConnectorExecuteRoute( + mockRouter as unknown as IRouter, + mockGetElser + ); + }); + + it('returns the expected response when subAction=invokeAI and actionTypeId=.gen-ai', async () => { + const mockRouter = { + versioned: { + post: jest.fn().mockImplementation(() => { + return { + addVersion: jest.fn().mockImplementation(async (_, handler) => { + const result = await handler( + mockContext, + { + ...mockRequest, + body: { + ...mockRequest.body, + subAction: 'invokeAI', + actionTypeId: '.gen-ai', + }, }, + 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 subAction=invokeAI and actionTypeId=.bedrock', async () => { + const mockRouter = { + versioned: { + post: jest.fn().mockImplementation(() => { + return { + addVersion: jest.fn().mockImplementation(async (_, handler) => { + const result = await handler( + mockContext, + { + ...mockRequest, + body: { + ...mockRequest.body, + subAction: 'invokeAI', + actionTypeId: '.bedrock', + }, + }, + mockResponse + ); + + expect(result).toEqual({ + body: { connector_id: 'mock-connector-id', data: mockActionResponse, status: 'ok' }, headers: { 'content-type': 'application/json', }, 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 e76b7cd337783..2d53106bacf13 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 @@ -31,7 +31,7 @@ import { POST_ACTIONS_CONNECTOR_EXECUTE } from '../../common/constants'; import { getLangChainMessages } from '../lib/langchain/helpers'; import { buildResponse } from '../lib/build_response'; import { ElasticAssistantRequestHandlerContext, GetElser } from '../types'; -import { ESQL_RESOURCE } from './knowledge_base/constants'; +import { ESQL_RESOURCE, KNOWLEDGE_BASE_INDEX_PATTERN } from './knowledge_base/constants'; import { callAgentExecutor } from '../lib/langchain/execute_custom_llm_chain'; import { DEFAULT_PLUGIN_NAME, @@ -41,6 +41,7 @@ import { import { getLangSmithTracer } from './evaluate/utils'; import { EsAnonymizationFieldsSchema } from '../ai_assistant_data_clients/anonymization_fields/types'; import { transformESSearchToAnonymizationFields } from '../ai_assistant_data_clients/anonymization_fields/helpers'; +import { ElasticsearchStore } from '../lib/langchain/elasticsearch_store/elasticsearch_store'; export const postActionsConnectorExecuteRoute = ( router: IRouter, @@ -315,7 +316,7 @@ export const postActionsConnectorExecuteRoute = ( []) as unknown as Array> ); - const elserId = await getElser(request, (await context.core).savedObjects.getClient()); + const elserId = await getElser(); const anonymizationFieldsRes = await anonymizationFieldsDataClient?.findDocuments({ @@ -323,6 +324,27 @@ export const postActionsConnectorExecuteRoute = ( page: 1, }); + // Create an ElasticsearchStore for KB interactions + // Setup with kbDataClient if `enableKnowledgeBaseByDefault` 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 esStore = new ElasticsearchStore( + esClient, + kbIndex, + logger, + telemetry, + elserId, + ESQL_RESOURCE, + kbDataClient + ); + const result: StreamResponseWithHeaders | StaticReturnType = await callAgentExecutor({ abortSignal, alertsIndexPattern: request.body.alertsIndexPattern, @@ -333,14 +355,10 @@ export const postActionsConnectorExecuteRoute = ( isEnabledKnowledgeBase: request.body.isEnabledKnowledgeBase ?? false, assistantTools, connectorId, - elserId, esClient, - isStream: - // TODO implement llmClass for bedrock streaming - // tracked here: https://github.com/elastic/security-team/issues/7363 - request.body.subAction !== 'invokeAI' && actionTypeId === '.gen-ai', + esStore, + isStream: request.body.subAction !== 'invokeAI', llmType: getLlmType(actionTypeId), - kbResource: ESQL_RESOURCE, langChainMessages, logger, onNewReplacements, @@ -348,7 +366,6 @@ export const postActionsConnectorExecuteRoute = ( request, replacements: request.body.replacements, size: request.body.size, - telemetry, traceOptions: { projectName: langSmithProject, tracers: getLangSmithTracer({ diff --git a/x-pack/plugins/elastic_assistant/server/routes/prompts/bulk_actions_route.ts b/x-pack/plugins/elastic_assistant/server/routes/prompts/bulk_actions_route.ts index d90b01b78cfa7..cfcd6d8cc05d6 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/prompts/bulk_actions_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/prompts/bulk_actions_route.ts @@ -112,7 +112,7 @@ const buildBulkResponse = ( export const bulkPromptsRoute = (router: ElasticAssistantPluginRouter, logger: Logger) => { router.versioned .post({ - access: 'public', + access: 'internal', path: ELASTIC_AI_ASSISTANT_PROMPTS_URL_BULK_ACTION, options: { tags: ['access:elasticAssistant'], @@ -123,7 +123,7 @@ export const bulkPromptsRoute = (router: ElasticAssistantPluginRouter, logger: L }) .addVersion( { - version: API_VERSIONS.public.v1, + version: API_VERSIONS.internal.v1, validate: { request: { body: buildRouteValidationWithZod(PerformBulkActionRequestBody), diff --git a/x-pack/plugins/elastic_assistant/server/routes/prompts/find_route.ts b/x-pack/plugins/elastic_assistant/server/routes/prompts/find_route.ts index f0f198b54eaf3..df2ec323bc356 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/prompts/find_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/prompts/find_route.ts @@ -23,7 +23,7 @@ import { UPGRADE_LICENSE_MESSAGE, hasAIAssistantLicense } from '../helpers'; export const findPromptsRoute = (router: ElasticAssistantPluginRouter, logger: Logger) => { router.versioned .get({ - access: 'public', + access: 'internal', path: ELASTIC_AI_ASSISTANT_PROMPTS_URL_FIND, options: { tags: ['access:elasticAssistant'], @@ -31,7 +31,7 @@ export const findPromptsRoute = (router: ElasticAssistantPluginRouter, logger: L }) .addVersion( { - version: API_VERSIONS.public.v1, + version: API_VERSIONS.internal.v1, validate: { request: { query: buildRouteValidationWithZod(FindPromptsRequestQuery), diff --git a/x-pack/plugins/elastic_assistant/server/routes/register_routes.ts b/x-pack/plugins/elastic_assistant/server/routes/register_routes.ts index 325f4a84ab8c7..fc0e30f4a925c 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/register_routes.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/register_routes.ts @@ -5,15 +5,10 @@ * 2.0. */ -import type { KibanaRequest, Logger, SavedObjectsClientContract } from '@kbn/core/server'; -import { once } from 'lodash/fp'; +import type { Logger } from '@kbn/core/server'; import { postAttackDiscoveryRoute } from './attack_discovery/post_attack_discovery'; -import { - ElasticAssistantPluginRouter, - ElasticAssistantPluginSetupDependencies, - GetElser, -} from '../types'; +import { ElasticAssistantPluginRouter, GetElser } from '../types'; import { createConversationRoute } from './user_conversations/create_route'; import { deleteConversationRoute } from './user_conversations/delete_route'; import { readConversationRoute } from './user_conversations/read_route'; @@ -36,7 +31,7 @@ import { findAnonymizationFieldsRoute } from './anonymization_fields/find_route' export const registerRoutes = ( router: ElasticAssistantPluginRouter, logger: Logger, - plugins: ElasticAssistantPluginSetupDependencies + getElserId: GetElser ) => { // Capabilities getCapabilitiesRoute(router); @@ -56,12 +51,6 @@ export const registerRoutes = ( // Knowledge Base deleteKnowledgeBaseRoute(router); - const getElserId: GetElser = once( - async (request: KibanaRequest, savedObjectsClient: SavedObjectsClientContract) => { - return (await plugins.ml.trainedModelsProvider(request, savedObjectsClient).getELSER()) - .model_id; - } - ); getKnowledgeBaseStatusRoute(router, getElserId); postKnowledgeBaseRoute(router, getElserId); 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 82e21a8cd8690..0a0864882df16 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,6 +81,18 @@ 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) => { + const currentUser = getCurrentUser(); + return this.assistantService.createAIAssistantKnowledgeBaseDataClient({ + spaceId: getSpaceId(), + logger: this.logger, + currentUser, + initializeKnowledgeBase, + }); + }), + getAIAssistantPromptsDataClient: memoize(() => { const currentUser = getCurrentUser(); return this.assistantService.createAIAssistantPromptsDataClient({ diff --git a/x-pack/plugins/elastic_assistant/server/routes/user_conversations/append_conversation_messages_route.ts b/x-pack/plugins/elastic_assistant/server/routes/user_conversations/append_conversation_messages_route.ts index dad21069e84c0..796c0d617fe5d 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/user_conversations/append_conversation_messages_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/user_conversations/append_conversation_messages_route.ts @@ -22,7 +22,7 @@ import { UPGRADE_LICENSE_MESSAGE, hasAIAssistantLicense } from '../helpers'; export const appendConversationMessageRoute = (router: ElasticAssistantPluginRouter) => { router.versioned .post({ - access: 'public', + access: 'internal', path: ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL_BY_ID_MESSAGES, options: { tags: ['access:elasticAssistant'], @@ -30,7 +30,7 @@ export const appendConversationMessageRoute = (router: ElasticAssistantPluginRou }) .addVersion( { - version: API_VERSIONS.public.v1, + version: API_VERSIONS.internal.v1, validate: { request: { body: buildRouteValidationWithZod(AppendConversationMessageRequestBody), 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 fafa5d6cc6e0e..0b41061265121 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 @@ -116,7 +116,7 @@ export const bulkActionConversationsRoute = ( ) => { router.versioned .post({ - access: 'public', + access: 'internal', path: ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL_BULK_ACTION, options: { tags: ['access:elasticAssistant'], @@ -127,7 +127,7 @@ export const bulkActionConversationsRoute = ( }) .addVersion( { - version: API_VERSIONS.public.v1, + version: API_VERSIONS.internal.v1, validate: { request: { body: buildRouteValidationWithZod(PerformBulkActionRequestBody), 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 281775cfb4e15..e66c83f77510d 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 @@ -21,7 +21,7 @@ import { UPGRADE_LICENSE_MESSAGE, hasAIAssistantLicense } from '../helpers'; export const createConversationRoute = (router: ElasticAssistantPluginRouter): void => { router.versioned .post({ - access: 'public', + access: 'internal', path: ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL, options: { @@ -30,7 +30,7 @@ export const createConversationRoute = (router: ElasticAssistantPluginRouter): v }) .addVersion( { - version: API_VERSIONS.public.v1, + version: API_VERSIONS.internal.v1, validate: { request: { body: buildRouteValidationWithZod(ConversationCreateProps), diff --git a/x-pack/plugins/elastic_assistant/server/routes/user_conversations/delete_route.ts b/x-pack/plugins/elastic_assistant/server/routes/user_conversations/delete_route.ts index 5d761c09f682c..b39f898eaeaa1 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/user_conversations/delete_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/user_conversations/delete_route.ts @@ -19,7 +19,7 @@ import { UPGRADE_LICENSE_MESSAGE, hasAIAssistantLicense } from '../helpers'; export const deleteConversationRoute = (router: ElasticAssistantPluginRouter) => { router.versioned .delete({ - access: 'public', + access: 'internal', path: ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL_BY_ID, options: { tags: ['access:elasticAssistant'], @@ -27,7 +27,7 @@ export const deleteConversationRoute = (router: ElasticAssistantPluginRouter) => }) .addVersion( { - version: API_VERSIONS.public.v1, + version: API_VERSIONS.internal.v1, validate: { request: { params: buildRouteValidationWithZod(DeleteConversationRequestParams), 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..8db36466c9bad 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 @@ -26,7 +26,7 @@ import { UPGRADE_LICENSE_MESSAGE, hasAIAssistantLicense } from '../helpers'; export const findUserConversationsRoute = (router: ElasticAssistantPluginRouter) => { router.versioned .get({ - access: 'public', + access: 'internal', path: ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL_FIND, options: { tags: ['access:elasticAssistant'], @@ -34,7 +34,7 @@ export const findUserConversationsRoute = (router: ElasticAssistantPluginRouter) }) .addVersion( { - version: API_VERSIONS.public.v1, + version: API_VERSIONS.internal.v1, validate: { request: { query: buildRouteValidationWithZod(FindConversationsRequestQuery), diff --git a/x-pack/plugins/elastic_assistant/server/routes/user_conversations/read_route.ts b/x-pack/plugins/elastic_assistant/server/routes/user_conversations/read_route.ts index dd540897b0ece..12020d7fa51d9 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/user_conversations/read_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/user_conversations/read_route.ts @@ -21,7 +21,7 @@ import { UPGRADE_LICENSE_MESSAGE, hasAIAssistantLicense } from '../helpers'; export const readConversationRoute = (router: ElasticAssistantPluginRouter) => { router.versioned .get({ - access: 'public', + access: 'internal', path: ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL_BY_ID, options: { tags: ['access:elasticAssistant'], @@ -29,7 +29,7 @@ export const readConversationRoute = (router: ElasticAssistantPluginRouter) => { }) .addVersion( { - version: API_VERSIONS.public.v1, + version: API_VERSIONS.internal.v1, validate: { request: { params: buildRouteValidationWithZod(ReadConversationRequestParams), diff --git a/x-pack/plugins/elastic_assistant/server/routes/user_conversations/update_route.ts b/x-pack/plugins/elastic_assistant/server/routes/user_conversations/update_route.ts index 213ea1e20a9ff..4a7fd5a9d67cb 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/user_conversations/update_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/user_conversations/update_route.ts @@ -24,7 +24,7 @@ import { UPGRADE_LICENSE_MESSAGE, hasAIAssistantLicense } from '../helpers'; export const updateConversationRoute = (router: ElasticAssistantPluginRouter) => { router.versioned .put({ - access: 'public', + access: 'internal', path: ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL_BY_ID, options: { tags: ['access:elasticAssistant'], @@ -32,7 +32,7 @@ export const updateConversationRoute = (router: ElasticAssistantPluginRouter) => }) .addVersion( { - version: API_VERSIONS.public.v1, + version: API_VERSIONS.internal.v1, validate: { request: { body: buildRouteValidationWithZod(ConversationUpdateProps), diff --git a/x-pack/plugins/elastic_assistant/server/services/app_context.test.ts b/x-pack/plugins/elastic_assistant/server/services/app_context.test.ts index 57ca4ea18651c..e91a0ec024c9e 100644 --- a/x-pack/plugins/elastic_assistant/server/services/app_context.test.ts +++ b/x-pack/plugins/elastic_assistant/server/services/app_context.test.ts @@ -102,6 +102,7 @@ describe('AppContextService', () => { it('should register and get features for a single plugin', () => { const pluginName = 'pluginName'; const features: AssistantFeatures = { + ...defaultAssistantFeatures, assistantModelEvaluation: true, }; @@ -116,10 +117,12 @@ describe('AppContextService', () => { it('should register and get features for multiple plugins', () => { const pluginOne = 'plugin1'; const featuresOne: AssistantFeatures = { + ...defaultAssistantFeatures, assistantModelEvaluation: true, }; const pluginTwo = 'plugin2'; const featuresTwo: AssistantFeatures = { + ...defaultAssistantFeatures, assistantModelEvaluation: false, }; @@ -134,9 +137,11 @@ describe('AppContextService', () => { it('should update features if registered again', () => { const pluginName = 'pluginName'; const featuresOne: AssistantFeatures = { + ...defaultAssistantFeatures, assistantModelEvaluation: true, }; const featuresTwo: AssistantFeatures = { + ...defaultAssistantFeatures, assistantModelEvaluation: false, }; diff --git a/x-pack/plugins/elastic_assistant/server/types.ts b/x-pack/plugins/elastic_assistant/server/types.ts index 63b62e8943c20..3a392eaa8c256 100755 --- a/x-pack/plugins/elastic_assistant/server/types.ts +++ b/x-pack/plugins/elastic_assistant/server/types.ts @@ -17,7 +17,6 @@ import type { IRouter, KibanaRequest, Logger, - SavedObjectsClientContract, } from '@kbn/core/server'; import { type MlPluginSetup } from '@kbn/ml-plugin/server'; import { DynamicStructuredTool, Tool } from '@langchain/core/tools'; @@ -37,11 +36,13 @@ import { LicensingApiRequestHandlerContext } from '@kbn/licensing-plugin/server' import { ActionsClientChatOpenAI, ActionsClientLlm, -} from '@kbn/elastic-assistant-common/impl/language_models'; + ActionsClientSimpleChatModel, +} from '@kbn/langchain/server'; import { AIAssistantConversationsDataClient } from './ai_assistant_data_clients/conversations'; import type { GetRegisteredFeatures, GetRegisteredTools } from './services/app_context'; import { AIAssistantDataClient } from './ai_assistant_data_clients'; +import { AIAssistantKnowledgeBaseDataClient } from './ai_assistant_data_clients/knowledge_base'; export const PLUGIN_ID = 'elasticAssistant' as const; @@ -110,6 +111,9 @@ export interface ElasticAssistantApiRequestHandlerContext { getSpaceId: () => string; getCurrentUser: () => AuthenticatedUser | null; getAIAssistantConversationsDataClient: () => Promise; + getAIAssistantKnowledgeBaseDataClient: ( + initializeKnowledgeBase: boolean + ) => Promise; getAIAssistantPromptsDataClient: () => Promise; getAIAssistantAnonymizationFieldsDataClient: () => Promise; telemetry: AnalyticsServiceSetup; @@ -129,10 +133,7 @@ export type ElasticAssistantPluginCoreSetupDependencies = CoreSetup< ElasticAssistantPluginStart >; -export type GetElser = ( - request: KibanaRequest, - savedObjectsClient: SavedObjectsClientContract -) => Promise | never; +export type GetElser = () => Promise | never; export interface InitAssistantResult { assistantResourcesInstalled: boolean; @@ -144,30 +145,30 @@ export interface InitAssistantResult { export interface AssistantResourceNames { componentTemplate: { conversations: string; + knowledgeBase: string; prompts: string; anonymizationFields: string; - kb: string; }; indexTemplate: { conversations: string; + knowledgeBase: string; prompts: string; anonymizationFields: string; - kb: string; }; aliases: { conversations: string; + knowledgeBase: string; prompts: string; anonymizationFields: string; - kb: string; }; indexPatterns: { conversations: string; + knowledgeBase: string; prompts: string; anonymizationFields: string; - kb: string; }; pipelines: { - kb: string; + knowledgeBase: string; }; } @@ -212,7 +213,7 @@ export interface AssistantToolParams { chain?: RetrievalQAChain; esClient: ElasticsearchClient; langChainTimeout?: number; - llm?: ActionsClientLlm | ActionsClientChatOpenAI; + llm?: ActionsClientLlm | ActionsClientChatOpenAI | ActionsClientSimpleChatModel; modelExists: boolean; onNewReplacements?: (newReplacements: Replacements) => void; replacements?: Replacements; diff --git a/x-pack/plugins/elastic_assistant/tsconfig.json b/x-pack/plugins/elastic_assistant/tsconfig.json index 20146c45df5fa..d4ce180d8496d 100644 --- a/x-pack/plugins/elastic_assistant/tsconfig.json +++ b/x-pack/plugins/elastic_assistant/tsconfig.json @@ -29,7 +29,6 @@ "@kbn/logging", "@kbn/ml-plugin", "@kbn/apm-utils", - "@kbn/core-analytics-server", "@kbn/elastic-assistant-common", "@kbn/core-http-router-server-mocks", "@kbn/data-stream-adapter", @@ -45,6 +44,9 @@ "@kbn/ml-response-stream", "@kbn/data-plugin", "@kbn/i18n", + "@kbn/core-security-common", + "@kbn/core-saved-objects-api-server", + "@kbn/langchain", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/enterprise_search/kibana.jsonc b/x-pack/plugins/enterprise_search/kibana.jsonc index d0767aae896fa..969ccab8b3c46 100644 --- a/x-pack/plugins/enterprise_search/kibana.jsonc +++ b/x-pack/plugins/enterprise_search/kibana.jsonc @@ -16,6 +16,7 @@ "licensing", "logsShared", "esUiShared", + "navigation", ], "optionalPlugins": [ "customIntegrations", diff --git a/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea_logic/kibana_logic.mock.ts b/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea_logic/kibana_logic.mock.ts index 1b3317e151956..5aa7f5236e269 100644 --- a/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea_logic/kibana_logic.mock.ts +++ b/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea_logic/kibana_logic.mock.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { of } from 'rxjs'; + import { chartPluginMock } from '@kbn/charts-plugin/public/mocks'; import { cloudMock } from '@kbn/cloud-plugin/public/mocks'; import { ApplicationStart, Capabilities } from '@kbn/core/public'; @@ -38,6 +40,7 @@ export const mockKibanaValues = { consolePlugin: null, data: dataPluginMock.createStartContract(), esConfig: { elasticsearch_host: 'https://your_deployment_url' }, + getChromeStyle$: jest.fn().mockReturnValue(of('classic')), guidedOnboarding: {}, history: mockHistory, indexMappingComponent: null, @@ -69,6 +72,7 @@ export const mockKibanaValues = { share: sharePluginMock.createStartContract(), ml: mlPluginMock.createStartContract(), uiSettings: uiSettingsServiceMock.createStartContract(), + updateSideNavDefinition: jest.fn(), user: null, }; diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/layout/page_template.test.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/layout/page_template.test.tsx index 65c3bd5cd7b6f..b43f1fbcee7d6 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/layout/page_template.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/layout/page_template.test.tsx @@ -5,23 +5,37 @@ * 2.0. */ +/* eslint-disable @kbn/i18n/strings_should_be_translated_with_i18n, @kbn/i18n/strings_should_be_translated_with_formatted_message */ + +import '../../../__mocks__/shallow_useeffect.mock'; +import { setMockValues } from '../../../__mocks__/kea_logic'; + import React from 'react'; +import { shallow } from 'enzyme'; +import { of } from 'rxjs'; + +const mockUseEnterpriseSearchAnalyticsNav = jest.fn().mockReturnValue([]); + jest.mock('../../../shared/layout/nav', () => ({ - useEnterpriseSearchAnalyticsNav: jest.fn().mockReturnValue([]), + useEnterpriseSearchAnalyticsNav: (...args: any[]) => mockUseEnterpriseSearchAnalyticsNav(...args), })); -import { shallow } from 'enzyme'; - import { SetAnalyticsChrome } from '../../../shared/kibana_chrome'; import { EnterpriseSearchPageTemplateWrapper } from '../../../shared/layout'; -import { useEnterpriseSearchAnalyticsNav } from '../../../shared/layout/nav'; import { SendEnterpriseSearchTelemetry } from '../../../shared/telemetry'; import { EnterpriseSearchAnalyticsPageTemplate } from './page_template'; +const mockValues = { + getChromeStyle$: () => of('classic'), + updateSideNavDefinition: jest.fn(), +}; + describe('EnterpriseSearchAnalyticsPageTemplate', () => { it('renders', () => { + setMockValues(mockValues); + const wrapper = shallow(
world
@@ -33,8 +47,34 @@ describe('EnterpriseSearchAnalyticsPageTemplate', () => { expect(wrapper.find('.hello').text()).toEqual('world'); }); + it('updates the side nav dynamic links', async () => { + const updateSideNavDefinition = jest.fn(); + setMockValues({ ...mockValues, updateSideNavDefinition }); + + const collectionsItems = [{ foo: 'bar' }]; + mockUseEnterpriseSearchAnalyticsNav.mockReturnValueOnce([ + { + id: 'build', + items: [ + { + id: 'analyticsCollections', + items: collectionsItems, + }, + ], + }, + ]); + + shallow(); + + expect(updateSideNavDefinition).toHaveBeenCalledWith({ + collections: collectionsItems, + }); + }); + describe('page chrome', () => { it('takes a breadcrumb array & renders a product-specific page chrome', () => { + setMockValues(mockValues); + const wrapper = shallow(); const setPageChrome = wrapper .find(EnterpriseSearchPageTemplateWrapper) @@ -47,6 +87,8 @@ describe('EnterpriseSearchAnalyticsPageTemplate', () => { describe('page telemetry', () => { it('takes a metric & renders product-specific telemetry viewed event', () => { + setMockValues(mockValues); + const wrapper = shallow( ); @@ -58,6 +100,8 @@ describe('EnterpriseSearchAnalyticsPageTemplate', () => { describe('props', () => { it('passes down any ...pageTemplateProps that EnterpriseSearchPageTemplateWrapper accepts', () => { + setMockValues(mockValues); + const wrapper = shallow( { }); it('passes down analytics name and paths to useEnterpriseSearchAnalyticsNav', () => { + setMockValues(mockValues); + const mockAnalyticsName = 'some_analytics_name'; shallow( { /> ); - expect(useEnterpriseSearchAnalyticsNav).toHaveBeenCalledWith(mockAnalyticsName, { - explorer: '/collections/some_analytics_name/explorer', - integration: '/collections/some_analytics_name/integrate', - overview: '/collections/some_analytics_name/overview', - }); + expect(mockUseEnterpriseSearchAnalyticsNav).toHaveBeenCalledWith( + mockAnalyticsName, + { + explorer: '/collections/some_analytics_name/explorer', + integration: '/collections/some_analytics_name/integrate', + overview: '/collections/some_analytics_name/overview', + }, + true + ); }); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/layout/page_template.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/layout/page_template.tsx index ea2a8ab6088f1..67180252e45d7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/layout/page_template.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/layout/page_template.tsx @@ -5,11 +5,17 @@ * 2.0. */ -import React from 'react'; +import React, { useCallback, useEffect } from 'react'; + +import { useValues } from 'kea'; + +import useObservable from 'react-use/lib/useObservable'; + +import type { EuiSideNavItemTypeEnhanced } from '@kbn/core-chrome-browser'; import { ENTERPRISE_SEARCH_CONTENT_PLUGIN } from '../../../../../common/constants'; import { generateEncodedPath } from '../../../shared/encode_path_params'; - +import { KibanaLogic } from '../../../shared/kibana'; import { SetAnalyticsChrome } from '../../../shared/kibana_chrome'; import { EnterpriseSearchPageTemplateWrapper, PageTemplateProps } from '../../../shared/layout'; import { useEnterpriseSearchAnalyticsNav } from '../../../shared/layout/nav'; @@ -27,26 +33,60 @@ interface EnterpriseSearchAnalyticsPageTemplateProps extends PageTemplateProps { export const EnterpriseSearchAnalyticsPageTemplate: React.FC< EnterpriseSearchAnalyticsPageTemplateProps > = ({ children, analyticsName, pageChrome, pageViewTelemetry, ...pageTemplateProps }) => { + const { updateSideNavDefinition, getChromeStyle$ } = useValues(KibanaLogic); + const chromeStyle = useObservable(getChromeStyle$(), 'classic'); + const alwaysReturnNavItems = true; + + const navItems = useEnterpriseSearchAnalyticsNav( + analyticsName, + analyticsName + ? { + explorer: generateEncodedPath(COLLECTION_EXPLORER_PATH, { + name: analyticsName, + }), + integration: generateEncodedPath(COLLECTION_INTEGRATE_PATH, { + name: analyticsName, + }), + overview: generateEncodedPath(COLLECTION_OVERVIEW_PATH, { + name: analyticsName, + }), + } + : undefined, + alwaysReturnNavItems + ); + + const getSelectedCollectionItems = useCallback( + ( + items?: Array> + ): Array> | undefined => { + if (!items) return undefined; + + const buildGroup = items.find((item) => item.id === 'build'); + if (!buildGroup || !buildGroup.items) return undefined; + + const searchAppsGroup = buildGroup.items.find((item) => item.id === 'analyticsCollections'); + + return searchAppsGroup?.items; + }, + [] + ); + + useEffect(() => { + // We update the new side nav definition with the selected collection items + updateSideNavDefinition({ collections: getSelectedCollectionItems(navItems) }); + }, [navItems, updateSideNavDefinition]); + + useEffect(() => { + return () => { + updateSideNavDefinition({ collections: undefined }); + }; + }, [updateSideNavDefinition]); + return ( } diff --git a/x-pack/plugins/enterprise_search/public/applications/applications/components/layout/page_template.test.tsx b/x-pack/plugins/enterprise_search/public/applications/applications/components/layout/page_template.test.tsx new file mode 100644 index 0000000000000..63dd0ed09fc50 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/applications/components/layout/page_template.test.tsx @@ -0,0 +1,56 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import '../../../__mocks__/shallow_useeffect.mock'; +import { setMockValues } from '../../../__mocks__/kea_logic'; + +import React from 'react'; + +import { shallow } from 'enzyme'; +import { of } from 'rxjs'; + +const mockUseEnterpriseSearchApplicationNav = jest.fn().mockReturnValue([]); + +jest.mock('../../../shared/layout', () => ({ + useEnterpriseSearchApplicationNav: (...args: any[]) => + mockUseEnterpriseSearchApplicationNav(...args), +})); + +import { EnterpriseSearchApplicationsPageTemplate } from './page_template'; + +const mockValues = { + getChromeStyle$: () => of('classic'), + renderHeaderActions: jest.fn(), + updateSideNavDefinition: jest.fn(), +}; + +describe('EnterpriseSearchApplicationsPageTemplate', () => { + it('updates the side nav dynamic links', async () => { + const updateSideNavDefinition = jest.fn(); + + setMockValues({ ...mockValues, updateSideNavDefinition }); + + const applicationsItems = [{ foo: 'bar' }]; + mockUseEnterpriseSearchApplicationNav.mockReturnValueOnce([ + { + id: 'build', + items: [ + { + id: 'searchApplications', + items: applicationsItems, + }, + ], + }, + ]); + + shallow(); + + expect(updateSideNavDefinition).toHaveBeenCalledWith({ + searchApps: applicationsItems, + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/applications/components/layout/page_template.tsx b/x-pack/plugins/enterprise_search/public/applications/applications/components/layout/page_template.tsx index 5a36b58733e3c..f8f390b1785b8 100644 --- a/x-pack/plugins/enterprise_search/public/applications/applications/components/layout/page_template.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/applications/components/layout/page_template.tsx @@ -5,10 +5,14 @@ * 2.0. */ -import React, { useLayoutEffect } from 'react'; +import React, { useCallback, useEffect, useLayoutEffect } from 'react'; import { useValues } from 'kea'; +import useObservable from 'react-use/lib/useObservable'; + +import type { EuiSideNavItemTypeEnhanced } from '@kbn/core-chrome-browser'; + import { ENTERPRISE_SEARCH_CONTENT_PLUGIN } from '../../../../../common/constants'; import { KibanaLogic } from '../../../shared/kibana'; import { SetEnterpriseSearchApplicationsChrome } from '../../../shared/kibana_chrome'; @@ -40,12 +44,33 @@ export const EnterpriseSearchApplicationsPageTemplate: React.FC< docLink = 'search_application', ...pageTemplateProps }) => { + const alwaysReturnNavItems = true; const navItems = useEnterpriseSearchApplicationNav( searchApplicationName, pageTemplateProps.isEmptyState, - hasSchemaConflicts + hasSchemaConflicts, + alwaysReturnNavItems + ); + + const { renderHeaderActions, updateSideNavDefinition, getChromeStyle$ } = useValues(KibanaLogic); + const chromeStyle = useObservable(getChromeStyle$(), 'classic'); + + const getSelectedAppItems = useCallback( + ( + items?: Array> + ): Array> | undefined => { + if (!items) return undefined; + + const buildGroup = items.find((item) => item.id === 'build'); + if (!buildGroup || !buildGroup.items) return undefined; + + const searchAppsGroup = buildGroup.items.find((item) => item.id === 'searchApplications'); + + return searchAppsGroup?.items; + }, + [] ); - const { renderHeaderActions } = useValues(KibanaLogic); + useLayoutEffect(() => { const docAction = { playground: PlaygroundHeaderDocsAction, @@ -57,11 +82,23 @@ export const EnterpriseSearchApplicationsPageTemplate: React.FC< renderHeaderActions(); }; }, []); + + useEffect(() => { + // We update the new side nav definition with the selected app items + updateSideNavDefinition({ searchApps: getSelectedAppItems(navItems) }); + }, [navItems, getSelectedAppItems, updateSideNavDefinition]); + + useEffect(() => { + return () => { + updateSideNavDefinition({ searchApps: undefined }); + }; + }, [updateSideNavDefinition]); + return ( { - const [searchParams] = useSearchParams(); - const index: string | null = searchParams.has('default-index') - ? searchParams.get('default-index') - : null; const { searchPlayground } = useValues(KibanaLogic); if (!searchPlayground) { return null; } return ( - + { ({ serviceType }) => serviceType === connector.service_type )?.docsUrl; - const isBeta = - !connector.service_type || - Boolean(BETA_CONNECTORS.find(({ serviceType }) => serviceType === connector.service_type)); + const isBeta = Boolean( + BETA_CONNECTORS.find(({ serviceType }) => serviceType === connector.service_type) + ); return ( <> diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/connector_stats.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/connector_stats.tsx index ec2edf2df0450..095844b4e04d4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/connector_stats.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/connector_stats.tsx @@ -10,6 +10,9 @@ import { useValues } from 'kea'; import { EuiBadge, + EuiButtonIcon, + EuiCode, + EuiCopy, EuiFlexGrid, EuiFlexGroup, EuiFlexItem, @@ -21,6 +24,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; import { Connector, ConnectorStatus, ElasticsearchIndex } from '@kbn/search-connectors'; @@ -127,40 +131,66 @@ export const ConnectorStats: React.FC = ({ connector, index
} footer={ - - - - - - + + + -

- {i18n.translate( - 'xpack.enterpriseSearch.connectors.connectorStats.p.DocumentsLabel', - { - defaultMessage: '{documentAmount} Documents', - values: { - documentAmount: indexData?.count ?? 0, - }, - } - )} -

+ {connector.id}, + }} + />
+ + + {(copy) => ( + + )} + +
- - {seeDocumentsLabel} - + {[ConnectorStatus.CONNECTED, ConnectorStatus.CONFIGURED].includes( + connector.status + ) && connector.index_name ? ( + + {configureLabel} + + ) : ( + + {configureLabel} + + )}
} @@ -169,7 +199,7 @@ export const ConnectorStats: React.FC = ({ connector, index = ({ connector, index {connector.index_name} - + + + + + + + {i18n.translate('xpack.enterpriseSearch.content.conectors.indexHealth', { + defaultMessage: 'Healthy', + })} + + +
) : ( @@ -201,33 +242,40 @@ export const ConnectorStats: React.FC = ({ connector, index ) } footer={ - + + + + + + + + +

+ {i18n.translate( + 'xpack.enterpriseSearch.connectors.connectorStats.p.DocumentsLabel', + { + defaultMessage: '{documentAmount} Documents', + values: { + documentAmount: indexData?.count ?? 0, + }, + } + )} +

+
+
+
+
- {[ConnectorStatus.CONNECTED, ConnectorStatus.CONFIGURED].includes( - connector.status - ) && connector.index_name ? ( - - {configureLabel} - - ) : ( - - {configureLabel} - - )} + + {seeDocumentsLabel} +
} diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index.test.tsx new file mode 100644 index 0000000000000..e5d64f960a22b --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index.test.tsx @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import '../../../__mocks__/shallow_useeffect.mock'; +import { setMockValues } from '../../../__mocks__/kea_logic'; + +import React from 'react'; + +const mockUseIndicesNav = jest.fn().mockReturnValue([]); + +jest.mock('react-router-dom', () => ({ + useParams: () => ({}), +})); + +jest.mock('./indices/indices_nav', () => ({ + useIndicesNav: (...args: any[]) => mockUseIndicesNav(...args), +})); + +import { shallow } from 'enzyme'; + +import { SearchIndex } from './search_index'; + +const mockValues = { + hasFilteringFeature: false, + updateSideNavDefinition: jest.fn(), +}; + +describe('SearchIndex', () => { + it('updates the side nav dynamic links', async () => { + const updateSideNavDefinition = jest.fn(); + + setMockValues({ ...mockValues, updateSideNavDefinition }); + + const indicesItems = [{ foo: 'bar' }]; + mockUseIndicesNav.mockReturnValueOnce(indicesItems); + + shallow(); + + expect(updateSideNavDefinition).toHaveBeenCalledWith({ + indices: indicesItems, + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index.tsx index a6e59f8e8e747..ea23a0b33479e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index.tsx @@ -39,6 +39,7 @@ import { SearchIndexDocuments } from './documents'; import { SearchIndexIndexMappings } from './index_mappings'; import { IndexNameLogic } from './index_name_logic'; import { IndexViewLogic } from './index_view_logic'; +import { useIndicesNav } from './indices/indices_nav'; import { SearchIndexOverview } from './overview'; import { SearchIndexPipelines } from './pipelines/pipelines'; @@ -76,8 +77,11 @@ export const SearchIndex: React.FC = () => { config, guidedOnboarding, productFeatures: { hasDefaultIngestPipeline }, + updateSideNavDefinition, } = useValues(KibanaLogic); + const indicesItems = useIndicesNav(); + useEffect(() => { const subscription = guidedOnboarding?.guidedOnboardingApi ?.isGuideStepActive$('appSearch', 'add_data') @@ -111,6 +115,17 @@ export const SearchIndex: React.FC = () => { return () => subscription?.unsubscribe(); }, [guidedOnboarding, index?.count]); + useEffect(() => { + // We update the new side nav definition with the selected indices items + updateSideNavDefinition({ indices: indicesItems }); + }, [indicesItems, updateSideNavDefinition]); + + useEffect(() => { + return () => { + updateSideNavDefinition({ indices: undefined }); + }; + }, [updateSideNavDefinition]); + const ALL_INDICES_TABS: EuiTabbedContentTab[] = [ { content: , diff --git a/x-pack/plugins/enterprise_search/public/applications/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/index.test.tsx index 6e2de90ee1f1d..1866d568af62f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/index.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/index.test.tsx @@ -23,6 +23,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { lensPluginMock } from '@kbn/lens-plugin/public/mocks'; import { licensingMock } from '@kbn/licensing-plugin/public/mocks'; import { mlPluginMock } from '@kbn/ml-plugin/public/mocks'; +import { navigationPluginMock } from '@kbn/navigation-plugin/public/mocks'; import { securityMock } from '@kbn/security-plugin/public/mocks'; import { sharePluginMock } from '@kbn/share-plugin/public/mocks'; @@ -46,12 +47,14 @@ describe('renderApp', () => { }, lens: lensPluginMock.createStartContract(), licensing: licensingMock.createStart(), + navigation: navigationPluginMock.createStartContract(), searchConnectors: searchConnectorsMock.createStart(), security: securityMock.createStart(), share: sharePluginMock.createStartContract(), ml: mlPluginMock.createStartContract(), user: {}, }, + updateSideNavDefinition: jest.fn(), } as any; const pluginData = { config: {}, diff --git a/x-pack/plugins/enterprise_search/public/applications/index.tsx b/x-pack/plugins/enterprise_search/public/applications/index.tsx index 1a06537bb6020..27241a0a628b8 100644 --- a/x-pack/plugins/enterprise_search/public/applications/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/index.tsx @@ -24,7 +24,7 @@ import { Router } from '@kbn/shared-ux-router'; import { DEFAULT_PRODUCT_FEATURES } from '../../common/constants'; import { ClientConfigType, InitialAppData, ProductAccess } from '../../common/types'; -import { PluginsStart, ClientData, ESConfig } from '../plugin'; +import { PluginsStart, ClientData, ESConfig, UpdateSideNavDefinitionFn } from '../plugin'; import { externalUrl } from './shared/enterprise_search_url'; import { mountFlashMessagesLogic } from './shared/flash_messages'; @@ -46,11 +46,13 @@ export const renderApp = ( core, plugins, isSidebarEnabled = true, + updateSideNavDefinition, }: { core: CoreStart; isSidebarEnabled: boolean; params: AppMountParameters; plugins: PluginsStart; + updateSideNavDefinition: UpdateSideNavDefinitionFn; }, { config, data, esConfig }: { config: ClientConfigType; data: ClientData; esConfig: ESConfig } ) => { @@ -124,6 +126,7 @@ export const renderApp = ( console: plugins.console, data: plugins.data, esConfig, + getChromeStyle$: chrome.getChromeStyle$, guidedOnboarding, history, indexMappingComponent, @@ -144,6 +147,7 @@ export const renderApp = ( setDocTitle: chrome.docTitle.change, share, uiSettings, + updateSideNavDefinition, user, }); const unmountLicensingLogic = mountLicensingLogic({ diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts b/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts index 1472c231aeba7..e4975452a29c5 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts @@ -18,6 +18,7 @@ import { ChromeBreadcrumb, ScopedHistory, IUiSettingsClient, + ChromeStart, } from '@kbn/core/public'; import { DataPublicPluginStart } from '@kbn/data-plugin/public'; @@ -32,7 +33,7 @@ import { AuthenticatedUser, SecurityPluginStart } from '@kbn/security-plugin/pub import { SharePluginStart } from '@kbn/share-plugin/public'; import { ClientConfigType, ProductAccess, ProductFeatures } from '../../../../common/types'; -import { ESConfig } from '../../../plugin'; +import { ESConfig, UpdateSideNavDefinitionFn } from '../../../plugin'; import { HttpLogic } from '../http'; import { createHref, CreateHrefOptions } from '../react_router_helpers'; @@ -50,6 +51,7 @@ export interface KibanaLogicProps { console?: ConsolePluginStart; data?: DataPublicPluginStart; esConfig: ESConfig; + getChromeStyle$: ChromeStart['getChromeStyle$']; guidedOnboarding?: GuidedOnboardingPluginStart; history: ScopedHistory; indexMappingComponent?: React.FC; @@ -67,6 +69,7 @@ export interface KibanaLogicProps { setDocTitle(title: string): void; share?: SharePluginStart; uiSettings?: IUiSettingsClient; + updateSideNavDefinition: UpdateSideNavDefinitionFn; user: AuthenticatedUser | null; } @@ -80,6 +83,7 @@ export interface KibanaValues { consolePlugin: ConsolePluginStart | null; data: DataPublicPluginStart | null; esConfig: ESConfig; + getChromeStyle$: ChromeStart['getChromeStyle$']; guidedOnboarding: GuidedOnboardingPluginStart | null; history: ScopedHistory; indexMappingComponent: React.FC | null; @@ -98,6 +102,7 @@ export interface KibanaValues { setDocTitle(title: string): void; share: SharePluginStart | null; uiSettings: IUiSettingsClient | null; + updateSideNavDefinition: UpdateSideNavDefinitionFn; user: AuthenticatedUser | null; } @@ -113,6 +118,7 @@ export const KibanaLogic = kea>({ consolePlugin: [props.console || null, {}], data: [props.data || null, {}], esConfig: [props.esConfig || { elasticsearch_host: ELASTICSEARCH_URL_PLACEHOLDER }, {}], + getChromeStyle$: [props.getChromeStyle$, {}], guidedOnboarding: [props.guidedOnboarding || null, {}], history: [props.history, {}], indexMappingComponent: [props.indexMappingComponent || null, {}], @@ -137,6 +143,7 @@ export const KibanaLogic = kea>({ setDocTitle: [props.setDocTitle, {}], share: [props.share || null, {}], uiSettings: [props.uiSettings, {}], + updateSideNavDefinition: [props.updateSideNavDefinition, {}], user: [props.user || null, {}], }), selectors: ({ selectors }) => ({ diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.test.tsx index 7ffb68ef228fa..3930e0f6c36f1 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.test.tsx @@ -273,6 +273,7 @@ describe('useEnterpriseSearchApplicationNav', () => { }, Object { "href": "/app/enterprise_search/applications/search_applications/my-test-engine/content", + "iconToString": undefined, "id": "enterpriseSearchApplicationsContent", "items": undefined, "name": { > Content , + "nameToString": "Content", }, Object { "href": "/app/enterprise_search/applications/search_applications/my-test-engine/connect", @@ -339,6 +341,7 @@ describe('useEnterpriseSearchApplicationNav', () => { expect(engineItem).toMatchInlineSnapshot(` Object { "href": "/app/enterprise_search/applications/search_applications/my-test-engine/content", + "iconToString": "warning", "id": "enterpriseSearchApplicationsContent", "items": undefined, "name": { type="warning" /> , + "nameToString": "Content", } `); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.tsx index ced35c94d6853..c2268d254197d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.tsx @@ -9,7 +9,8 @@ import React from 'react'; import { useValues } from 'kea'; -import { EuiFlexGroup, EuiIcon, EuiSideNavItemType, EuiText } from '@elastic/eui'; +import { EuiFlexGroup, EuiIcon, EuiText } from '@elastic/eui'; +import type { EuiSideNavItemTypeEnhanced } from '@kbn/core-chrome-browser'; import { i18n } from '@kbn/i18n'; import { @@ -38,12 +39,18 @@ import { KibanaLogic } from '../kibana'; import { generateNavLink } from './nav_link_helpers'; -export const useEnterpriseSearchNav = () => { +/** + * Hook to generate the Enterprise Search navigation items + * + * @param alwaysReturn Flag to always return the nav items, even if the sidebar is disabled + * @returns The Enterprise Search navigation items + */ +export const useEnterpriseSearchNav = (alwaysReturn = false) => { const { isSidebarEnabled, productAccess } = useValues(KibanaLogic); const indicesNavItems = useIndicesNav(); - if (!isSidebarEnabled) return undefined; + if (!isSidebarEnabled && !alwaysReturn) return undefined; - const navItems: Array> = [ + const navItems: Array> = [ { id: 'home', name: ( @@ -224,9 +231,10 @@ export const useEnterpriseSearchNav = () => { export const useEnterpriseSearchApplicationNav = ( searchApplicationName?: string, isEmptyState?: boolean, - hasSchemaConflicts?: boolean + hasSchemaConflicts?: boolean, + alwaysReturn?: boolean ) => { - const navItems = useEnterpriseSearchNav(); + const navItems = useEnterpriseSearchNav(alwaysReturn); if (!navItems) return undefined; if (!searchApplicationName) return navItems; const applicationsItem = navItems.find((item) => item.id === 'build'); @@ -264,6 +272,8 @@ export const useEnterpriseSearchApplicationNav = ( }), }, { + // Required for the new side nav + iconToString: hasSchemaConflicts ? 'warning' : undefined, id: 'enterpriseSearchApplicationsContent', name: ( @@ -273,6 +283,13 @@ export const useEnterpriseSearchApplicationNav = ( {hasSchemaConflicts && } ), + // Required for the new side nav + nameToString: i18n.translate( + 'xpack.enterpriseSearch.nav.searchApplication.contentTitle', + { + defaultMessage: 'Content', + } + ), ...generateNavLink({ shouldNotCreateHref: true, shouldShowActiveForSubroutes: true, @@ -317,9 +334,10 @@ export const useEnterpriseSearchAnalyticsNav = ( explorer: string; integration: string; overview: string; - } + }, + alwaysReturn?: boolean ) => { - const navItems = useEnterpriseSearchNav(); + const navItems = useEnterpriseSearchNav(alwaysReturn); if (!navItems) return undefined; diff --git a/x-pack/plugins/enterprise_search/public/applications/test_helpers/test_utils.test_helper.tsx b/x-pack/plugins/enterprise_search/public/applications/test_helpers/test_utils.test_helper.tsx index b696054ea9fb2..02102d8cc4dc4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/test_helpers/test_utils.test_helper.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/test_helpers/test_utils.test_helper.tsx @@ -12,6 +12,8 @@ import { render as testingLibraryRender } from '@testing-library/react'; import { LogicWrapper, Provider, resetContext } from 'kea'; +import { of } from 'rxjs'; + import { chartPluginMock } from '@kbn/charts-plugin/public/mocks'; import { cloudMock } from '@kbn/cloud-plugin/public/mocks'; import { ApplicationStart } from '@kbn/core-application-browser'; @@ -53,6 +55,7 @@ export const mockKibanaProps: KibanaLogicProps = { esConfig: { elasticsearch_host: 'https://your_deployment_url', }, + getChromeStyle$: jest.fn().mockReturnValue(of('classic')), guidedOnboarding: {}, history: mockHistory, indexMappingComponent: () => { @@ -87,6 +90,7 @@ export const mockKibanaProps: KibanaLogicProps = { setDocTitle: jest.fn(), share: sharePluginMock.createStartContract(), uiSettings: uiSettingsServiceMock.createStartContract(), + updateSideNavDefinition: jest.fn(), user: null, }; diff --git a/x-pack/plugins/enterprise_search/public/navigation_tree.ts b/x-pack/plugins/enterprise_search/public/navigation_tree.ts new file mode 100644 index 0000000000000..310a0eb24b263 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/navigation_tree.ts @@ -0,0 +1,344 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 Observable, map, debounceTime } from 'rxjs'; + +import type { EuiSideNavItemType } from '@elastic/eui'; +import type { + NavigationTreeDefinition, + NodeDefinition, + EuiSideNavItemTypeEnhanced, +} from '@kbn/core-chrome-browser'; +import { i18n } from '@kbn/i18n'; + +import type { AddSolutionNavigationArg } from '@kbn/navigation-plugin/public'; + +import { SEARCH_APPLICATIONS_PATH } from './applications/applications/routes'; +import { SEARCH_INDICES_PATH } from './applications/enterprise_search_content/routes'; + +export interface DynamicSideNavItems { + collections?: Array>; + indices?: Array>; + searchApps?: Array>; +} + +const title = i18n.translate( + 'xpack.enterpriseSearch.searchNav.headerSolutionSwitcher.searchSolutionTitle', + { + defaultMessage: 'Search', + } +); +const icon = 'logoElasticsearch'; + +const euiItemTypeToNodeDefinition = ({ + items, + href, + iconToString, + id, + isSelected = false, + name, + nameToString, + onClick, +}: EuiSideNavItemTypeEnhanced): NodeDefinition => { + const isAccordion = items !== undefined; + + const node: NodeDefinition = { + children: isAccordion ? items.map(euiItemTypeToNodeDefinition) : undefined, + getIsActive: () => isSelected, + href, + icon: iconToString, + id: `${id}`, + onClick: onClick + ? (e) => { + e.stopPropagation(); + onClick(e); + } + : undefined, + title: typeof name === 'string' ? name : nameToString, + ...(isAccordion ? { isCollapsible: false, renderAs: 'accordion' } : {}), + }; + + return node; +}; + +export const getNavigationTreeDefinition = ({ + dynamicItems$, +}: { + dynamicItems$: Observable; +}): AddSolutionNavigationArg => { + return { + dataTestSubj: 'searchSideNav', + homePage: 'enterpriseSearch', + icon, + id: 'es', + navigationTree$: dynamicItems$.pipe( + debounceTime(10), + map(({ indices, searchApps, collections }) => { + const navTree: NavigationTreeDefinition = { + body: [ + { type: 'recentlyAccessed' }, + { + breadcrumbStatus: 'hidden', + children: [ + { + link: 'enterpriseSearch', + }, + { + getIsActive: ({ pathNameSerialized, prepend }) => { + return pathNameSerialized.startsWith(prepend('/app/dev_tools')); + }, + id: 'dev_tools', + link: 'dev_tools:console', + title: i18n.translate('xpack.enterpriseSearch.searchNav.devTools', { + defaultMessage: 'Dev Tools', + }), + }, + { + children: [ + { + link: 'discover', + }, + { + getIsActive: ({ pathNameSerialized, prepend }) => { + return pathNameSerialized.startsWith(prepend('/app/dashboards')); + }, + link: 'dashboards', + }, + ], + id: 'kibana', + title: i18n.translate('xpack.enterpriseSearch.searchNav.kibana', { + defaultMessage: 'Kibana', + }), + }, + { + children: [ + { + getIsActive: ({ pathNameSerialized, prepend }) => { + const someSubItemSelected = indices?.some((index) => + index.items?.some((item) => item.isSelected) + ); + + if (someSubItemSelected) return false; + + return ( + pathNameSerialized === + prepend(`/app/enterprise_search/content${SEARCH_INDICES_PATH}`) + ); + }, + link: 'enterpriseSearchContent:searchIndices', + renderAs: 'item', + ...(indices + ? { + children: indices.map(euiItemTypeToNodeDefinition), + isCollapsible: false, + renderAs: 'accordion', + } + : {}), + }, + { link: 'enterpriseSearchContent:connectors' }, + { link: 'enterpriseSearchContent:webCrawlers' }, + ], + id: 'content', + title: i18n.translate('xpack.enterpriseSearch.searchNav.content', { + defaultMessage: 'Content', + }), + }, + { + children: [ + { + link: 'enterpriseSearchApplications:playground', + }, + { + getIsActive: ({ pathNameSerialized, prepend }) => { + const someSubItemSelected = searchApps?.some((app) => + app.items?.some((item) => item.isSelected) + ); + + if (someSubItemSelected) return false; + + return ( + pathNameSerialized === + prepend(`/app/enterprise_search/applications${SEARCH_APPLICATIONS_PATH}`) + ); + }, + link: 'enterpriseSearchApplications:searchApplications', + renderAs: 'item', + title: i18n.translate( + 'xpack.enterpriseSearch.searchNav.build.searchApplications', + { + defaultMessage: 'Search applications', + } + ), + ...(searchApps + ? { + children: searchApps.map(euiItemTypeToNodeDefinition), + isCollapsible: false, + renderAs: 'accordion', + } + : {}), + }, + { + getIsActive: ({ pathNameSerialized, prepend }) => { + const someSubItemSelected = collections?.some((collection) => + collection.items?.some((item) => item.isSelected) + ); + + if (someSubItemSelected) return false; + + return pathNameSerialized === prepend(`/app/enterprise_search/analytics`); + }, + link: 'enterpriseSearchAnalytics', + renderAs: 'item', + ...(collections + ? { + children: collections.map(euiItemTypeToNodeDefinition), + isCollapsible: false, + renderAs: 'accordion', + } + : {}), + }, + ], + id: 'build', + title: i18n.translate('xpack.enterpriseSearch.searchNav.build', { + defaultMessage: 'Build', + }), + }, + { + children: [ + { + getIsActive: ({ pathNameSerialized, prepend }) => { + return pathNameSerialized.startsWith( + prepend('/app/enterprise_search/app_search') + ); + }, + link: 'appSearch:engines', + title: i18n.translate( + 'xpack.enterpriseSearch.searchNav.entsearch.appSearch', + { + defaultMessage: 'App Search', + } + ), + }, + { + link: 'workplaceSearch', + }, + ], + id: 'entsearch', + title: i18n.translate('xpack.enterpriseSearch.searchNav.entsearch', { + defaultMessage: 'Enterprise Search', + }), + }, + ], + defaultIsCollapsed: false, + icon, + id: 'search_project_nav', + isCollapsible: false, + title, + type: 'navGroup', + }, + ], + footer: [ + { + breadcrumbStatus: 'hidden', + children: [ + { + link: 'ml:modelManagement', + title: i18n.translate( + 'xpack.enterpriseSearch.searchNav.management.trainedModels', + { + defaultMessage: 'Trained models', + } + ), + }, + { + children: [ + { + children: [ + { link: 'management:ingest_pipelines' }, + { link: 'management:pipelines' }, + ], + title: 'Ingest', + }, + { + children: [ + { link: 'management:index_management' }, + { link: 'management:index_lifecycle_management' }, + { link: 'management:snapshot_restore' }, + { link: 'management:rollup_jobs' }, + { link: 'management:transform' }, + { link: 'management:cross_cluster_replication' }, + { link: 'management:remote_clusters' }, + { link: 'management:migrate_data' }, + ], + title: 'Data', + }, + { + children: [ + { link: 'management:triggersActions' }, + { link: 'management:cases' }, + { link: 'management:triggersActionsConnectors' }, + { link: 'management:reporting' }, + { link: 'management:jobsListLink' }, + { link: 'management:watcher' }, + { link: 'management:maintenanceWindows' }, + ], + title: 'Alerts and Insights', + }, + { + children: [ + { link: 'management:users' }, + { link: 'management:roles' }, + { link: 'management:api_keys' }, + { link: 'management:role_mappings' }, + ], + title: 'Security', + }, + { + children: [ + { link: 'management:dataViews' }, + { link: 'management:filesManagement' }, + { link: 'management:objects' }, + { link: 'management:tags' }, + { link: 'management:search_sessions' }, + { link: 'management:aiAssistantManagementSelection' }, + { link: 'management:spaces' }, + { link: 'management:settings' }, + ], + title: 'Kibana', + }, + { + children: [ + { link: 'management:license_management' }, + { link: 'management:upgrade_assistant' }, + ], + title: 'Stack', + }, + ], + link: 'management', + renderAs: 'panelOpener', + spaceBefore: null, + title: i18n.translate('xpack.enterpriseSearch.searchNav.mngt', { + defaultMessage: 'Stack Management', + }), + }, + ], + icon: 'gear', + id: 'project_settings_project_nav', + title: i18n.translate('xpack.enterpriseSearch.searchNav.management', { + defaultMessage: 'Management', + }), + type: 'navGroup', + }, + ], + }; + + return navTree; + }) + ), + title, + }; +}; diff --git a/x-pack/plugins/enterprise_search/public/plugin.ts b/x-pack/plugins/enterprise_search/public/plugin.ts index 60134aafd8534..96c4bab2b8059 100644 --- a/x-pack/plugins/enterprise_search/public/plugin.ts +++ b/x-pack/plugins/enterprise_search/public/plugin.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { firstValueFrom } from 'rxjs'; +import { BehaviorSubject, firstValueFrom } from 'rxjs'; import { ChartsPluginStart } from '@kbn/charts-plugin/public'; import { CloudSetup, CloudStart } from '@kbn/cloud-plugin/public'; @@ -29,6 +29,7 @@ import type { IndexManagementPluginStart } from '@kbn/index-management'; import { LensPublicStart } from '@kbn/lens-plugin/public'; import { LicensingPluginStart } from '@kbn/licensing-plugin/public'; import { MlPluginStart } from '@kbn/ml-plugin/public'; +import type { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public'; import { ELASTICSEARCH_URL_PLACEHOLDER } from '@kbn/search-api-panels/constants'; import { SearchConnectorsPluginStart } from '@kbn/search-connectors-plugin/public'; import { SearchPlaygroundPluginStart } from '@kbn/search-playground/public'; @@ -63,6 +64,7 @@ import { } from './applications/enterprise_search_content/routes'; import { docLinks } from './applications/shared/doc_links'; +import type { DynamicSideNavItems } from './navigation_tree'; export interface ClientData extends InitialAppData { errorConnectingMessage?: string; @@ -89,6 +91,7 @@ export interface PluginsStart { lens?: LensPublicStart; licensing?: LicensingPluginStart; ml?: MlPluginStart; + navigation: NavigationPublicPluginStart; searchConnectors?: SearchConnectorsPluginStart; searchPlayground?: SearchPlaygroundPluginStart; security?: SecurityPluginStart; @@ -99,6 +102,8 @@ export interface ESConfig { elasticsearch_host: string; } +export type UpdateSideNavDefinitionFn = (items: Partial) => void; + const contentLinks: AppDeepLink[] = [ { id: 'connectors', @@ -205,7 +210,13 @@ export class EnterpriseSearchPlugin implements Plugin { this.isSidebarEnabled = style === 'classic'; }); - return { core: coreStart, isSidebarEnabled: this.isSidebarEnabled, params, plugins }; + return { + core: coreStart, + isSidebarEnabled: this.isSidebarEnabled, + params, + plugins, + updateSideNavDefinition: this.updateSideNavDefinition.bind(this), + }; } private getPluginData() { @@ -522,7 +533,9 @@ export class EnterpriseSearchPlugin implements Plugin { } } - public start(core: CoreStart) { + private readonly sideNavDynamicItems$ = new BehaviorSubject({}); + + public start(core: CoreStart, plugins: PluginsStart) { if (!this.config.ui?.enabled) { return; } @@ -530,10 +543,20 @@ export class EnterpriseSearchPlugin implements Plugin { // race conditions with our apps' `routes.ts` being initialized before `renderApp()` docLinks.setDocLinks(core.docLinks); + import('./navigation_tree').then(({ getNavigationTreeDefinition }) => { + return plugins.navigation.addSolutionNavigation( + getNavigationTreeDefinition({ dynamicItems$: this.sideNavDynamicItems$ }) + ); + }); + // Return empty start contract rather than void in order for plugins // that depend on the enterprise search plugin to determine whether it is enabled or not return {}; } public stop() {} + + private updateSideNavDefinition = (items: Partial) => { + this.sideNavDynamicItems$.next({ ...this.sideNavDynamicItems$.getValue(), ...items }); + }; } diff --git a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.ts b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.ts index eabd377a43f13..1d240df3d9cf9 100644 --- a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.ts +++ b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.ts @@ -14,7 +14,7 @@ import { schema } from '@kbn/config-schema'; import { i18n } from '@kbn/i18n'; -import { deleteConnectorById, deleteConnectorSecret } from '@kbn/search-connectors'; +import { deleteConnectorSecret, updateConnectorIndexName } from '@kbn/search-connectors'; import { fetchConnectorByIndexName, fetchConnectors, @@ -207,7 +207,8 @@ export function registerIndexRoutes({ } if (connector) { - await deleteConnectorById(client.asCurrentUser, connector.id); + // detach the deleted index without removing the connector + await updateConnectorIndexName(client.asCurrentUser, connector.id, null); if (connector.api_key_id) { await client.asCurrentUser.security.invalidateApiKey({ ids: [connector.api_key_id] }); } diff --git a/x-pack/plugins/enterprise_search/tsconfig.json b/x-pack/plugins/enterprise_search/tsconfig.json index 56232cd73f256..53f364e26cac2 100644 --- a/x-pack/plugins/enterprise_search/tsconfig.json +++ b/x-pack/plugins/enterprise_search/tsconfig.json @@ -76,6 +76,8 @@ "@kbn/react-kibana-context-theme", "@kbn/search-types", "@kbn/cloud", - "@kbn/try-in-console" + "@kbn/try-in-console", + "@kbn/core-chrome-browser", + "@kbn/navigation-plugin" ] } diff --git a/x-pack/plugins/fleet/common/constants/authz.ts b/x-pack/plugins/fleet/common/constants/authz.ts index 72c975af1a3d1..1c9ab5a402789 100644 --- a/x-pack/plugins/fleet/common/constants/authz.ts +++ b/x-pack/plugins/fleet/common/constants/authz.ts @@ -162,6 +162,12 @@ export const ENDPOINT_PRIVILEGES: Record = deepFreez privilegeType: 'api', privilegeName: 'writeExecuteOperations', }, + writeScanOperations: { + appId: DEFAULT_APP_CATEGORIES.security.id, + privilegeSplit: '-', + privilegeType: 'api', + privilegeName: 'writeScanOperations', + }, }); export const ENDPOINT_EXCEPTIONS_PRIVILEGES: Record = deepFreeze({ diff --git a/x-pack/plugins/fleet/common/constants/index.ts b/x-pack/plugins/fleet/common/constants/index.ts index 3c275f87e1aea..51d51db9e761f 100644 --- a/x-pack/plugins/fleet/common/constants/index.ts +++ b/x-pack/plugins/fleet/common/constants/index.ts @@ -56,4 +56,6 @@ export const DATA_TIERS = ['data_hot']; export const FLEET_ENROLLMENT_API_PREFIX = 'fleet-enrollment-api-keys'; +export const REQUEST_DIAGNOSTICS_TIMEOUT_MS = 3 * 60 * 60 * 1000; // 3 hours; + export * from './mappings'; diff --git a/x-pack/plugins/fleet/common/constants/routes.ts b/x-pack/plugins/fleet/common/constants/routes.ts index 9fe1f4b49d7d8..ee775ff1dbdd8 100644 --- a/x-pack/plugins/fleet/common/constants/routes.ts +++ b/x-pack/plugins/fleet/common/constants/routes.ts @@ -160,6 +160,7 @@ export const AGENT_API_ROUTES = { LIST_TAGS_PATTERN: `${API_ROOT}/agents/tags`, LIST_UPLOADS_PATTERN: `${API_ROOT}/agents/{agentId}/uploads`, GET_UPLOAD_FILE_PATTERN: `${API_ROOT}/agents/files/{fileId}/{fileName}`, + DELETE_UPLOAD_FILE_PATTERN: `${API_ROOT}/agents/files/{fileId}`, }; export const ENROLLMENT_API_KEY_ROUTES = { diff --git a/x-pack/plugins/fleet/common/openapi/bundled.json b/x-pack/plugins/fleet/common/openapi/bundled.json index 9a86cbe6f9fd1..5cbc85dd12ce1 100644 --- a/x-pack/plugins/fleet/common/openapi/bundled.json +++ b/x-pack/plugins/fleet/common/openapi/bundled.json @@ -2503,7 +2503,7 @@ ] } }, - "/agents/files@{fileId}@{fileName}": { + "/agents/files/{fileId}/{fileName}": { "parameters": [ { "schema": { @@ -2559,6 +2559,53 @@ "operationId": "get-agent-upload-file" } }, + "/agents/files/{fileId}": { + "parameters": [ + { + "schema": { + "type": "string" + }, + "name": "fileId", + "in": "path", + "required": true + } + ], + "delete": { + "summary": "Delete file uploaded by agent", + "tags": [ + "Agents" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "body": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "deleted": { + "type": "boolean" + } + } + } + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/error" + } + }, + "operationId": "delete-agent-upload-file" + } + }, "/agents/{agentId}/reassign": { "parameters": [ { @@ -7399,6 +7446,9 @@ }, "title": { "type": "string" + }, + "requires_root": { + "type": "boolean" } }, "required": [ diff --git a/x-pack/plugins/fleet/common/openapi/bundled.yaml b/x-pack/plugins/fleet/common/openapi/bundled.yaml index 16137b6f8dd27..f0f5bf761ada8 100644 --- a/x-pack/plugins/fleet/common/openapi/bundled.yaml +++ b/x-pack/plugins/fleet/common/openapi/bundled.yaml @@ -1581,7 +1581,7 @@ paths: operationId: agent-action-cancel parameters: - $ref: '#/components/parameters/kbn_xsrf' - /agents/files@{fileId}@{fileName}: + /agents/files/{fileId}/{fileName}: parameters: - schema: type: string @@ -1616,6 +1616,35 @@ paths: '400': $ref: '#/components/responses/error' operationId: get-agent-upload-file + /agents/files/{fileId}: + parameters: + - schema: + type: string + name: fileId + in: path + required: true + delete: + summary: Delete file uploaded by agent + tags: + - Agents + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + body: + type: object + properties: + id: + type: string + deleted: + type: boolean + '400': + $ref: '#/components/responses/error' + operationId: delete-agent-upload-file /agents/{agentId}/reassign: parameters: - schema: @@ -4747,6 +4776,8 @@ components: type: string title: type: string + requires_root: + type: boolean required: - name - version diff --git a/x-pack/plugins/fleet/common/openapi/components/schemas/agent_policy.yaml b/x-pack/plugins/fleet/common/openapi/components/schemas/agent_policy.yaml index 02f302e025d67..5f8a2f578132e 100644 --- a/x-pack/plugins/fleet/common/openapi/components/schemas/agent_policy.yaml +++ b/x-pack/plugins/fleet/common/openapi/components/schemas/agent_policy.yaml @@ -51,7 +51,7 @@ properties: agents: type: number unprivileged_agents: - type: number + type: number agent_features: type: array items: diff --git a/x-pack/plugins/fleet/common/openapi/components/schemas/new_package_policy.yaml b/x-pack/plugins/fleet/common/openapi/components/schemas/new_package_policy.yaml index b7b904badad08..7fb94651b9fee 100644 --- a/x-pack/plugins/fleet/common/openapi/components/schemas/new_package_policy.yaml +++ b/x-pack/plugins/fleet/common/openapi/components/schemas/new_package_policy.yaml @@ -13,6 +13,8 @@ properties: type: string title: type: string + requires_root: + type: boolean required: - name - version diff --git a/x-pack/plugins/fleet/common/openapi/entrypoint.yaml b/x-pack/plugins/fleet/common/openapi/entrypoint.yaml index 8feb15cb8698e..04203cc5d2e6b 100644 --- a/x-pack/plugins/fleet/common/openapi/entrypoint.yaml +++ b/x-pack/plugins/fleet/common/openapi/entrypoint.yaml @@ -77,8 +77,10 @@ paths: $ref: 'paths/agents@{agent_id}@actions.yaml' '/agents/{agentId}/actions/{actionId}/cancel': $ref: 'paths/agents@{agent_id}@actions@{action_id}@cancel.yaml' - '/agents/files@{fileId}@{fileName}': + '/agents/files/{fileId}/{fileName}': $ref: 'paths/agents@files@{file_id}@{file_name}.yaml' + '/agents/files/{fileId}': + $ref: 'paths/agents@files@{file_id}.yaml' '/agents/{agentId}/reassign': $ref: 'paths/agents@{agent_id}@reassign.yaml' '/agents/{agentId}/unenroll': diff --git a/x-pack/plugins/fleet/common/openapi/paths/agents@files@{file_id}.yaml b/x-pack/plugins/fleet/common/openapi/paths/agents@files@{file_id}.yaml new file mode 100644 index 0000000000000..4507cb8ce456d --- /dev/null +++ b/x-pack/plugins/fleet/common/openapi/paths/agents@files@{file_id}.yaml @@ -0,0 +1,28 @@ +parameters: + - schema: + type: string + name: fileId + in: path + required: true +delete: + summary: Delete file uploaded by agent + tags: + - Agents + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + body: + type: object + properties: + id: + type: string + deleted: + type: boolean + '400': + $ref: ../components/responses/error.yaml + operationId: delete-agent-upload-file diff --git a/x-pack/plugins/fleet/common/services/package_helpers.test.ts b/x-pack/plugins/fleet/common/services/package_helpers.test.ts index 71d3a9018ed5e..0004ddfe40424 100644 --- a/x-pack/plugins/fleet/common/services/package_helpers.test.ts +++ b/x-pack/plugins/fleet/common/services/package_helpers.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { isRootPrivilegesRequired } from './package_helpers'; +import { getRootIntegrations, isRootPrivilegesRequired } from './package_helpers'; describe('isRootPrivilegesRequired', () => { it('should return true if root privileges is required at root level', () => { @@ -38,3 +38,44 @@ describe('isRootPrivilegesRequired', () => { expect(res).toBe(false); }); }); + +describe('getRootIntegrations', () => { + it('should return packages that require root', () => { + const res = getRootIntegrations([ + { + package: { + requires_root: true, + name: 'auditd_manager', + title: 'Auditd Manager', + }, + } as any, + { + package: { + requires_root: false, + name: 'system', + title: 'System', + }, + } as any, + { + package: { + name: 'test', + title: 'Test', + }, + } as any, + { + package: { + requires_root: true, + name: 'auditd_manager', + title: 'Auditd Manager', + }, + } as any, + {} as any, + ]); + expect(res).toEqual([{ name: 'auditd_manager', title: 'Auditd Manager' }]); + }); + + it('should return empty array if no packages require root', () => { + const res = getRootIntegrations([]); + expect(res).toEqual([]); + }); +}); diff --git a/x-pack/plugins/fleet/common/services/package_helpers.ts b/x-pack/plugins/fleet/common/services/package_helpers.ts index 0282d218cec39..18c9368cd388a 100644 --- a/x-pack/plugins/fleet/common/services/package_helpers.ts +++ b/x-pack/plugins/fleet/common/services/package_helpers.ts @@ -5,7 +5,9 @@ * 2.0. */ -import type { PackageInfo } from '../types'; +import { uniqBy } from 'lodash'; + +import type { PackageInfo, PackagePolicy } from '../types'; /** * Return true if a package need Elastic Agent to be run as root/administrator @@ -16,3 +18,14 @@ export function isRootPrivilegesRequired(packageInfo: PackageInfo) { packageInfo.data_streams?.some((d) => d.agent?.privileges?.root) ); } + +export function getRootIntegrations( + packagePolicies: PackagePolicy[] +): Array<{ name: string; title: string }> { + return uniqBy( + packagePolicies + .map((policy) => policy.package) + .filter((pkg) => (pkg && pkg.requires_root) || false), + (pkg) => pkg!.name + ).map((pkg) => ({ name: pkg!.name, title: pkg!.title })); +} diff --git a/x-pack/plugins/fleet/common/services/routes.ts b/x-pack/plugins/fleet/common/services/routes.ts index 5d8f2c48914da..76b963949699a 100644 --- a/x-pack/plugins/fleet/common/services/routes.ts +++ b/x-pack/plugins/fleet/common/services/routes.ts @@ -236,6 +236,8 @@ export const agentRouteService = { '{fileName}', fileName ), + getAgentFileDeletePath: (fileId: string) => + AGENT_API_ROUTES.DELETE_UPLOAD_FILE_PATTERN.replace('{fileId}', fileId), getAgentsByActionsPath: () => AGENT_API_ROUTES.LIST_PATTERN, }; diff --git a/x-pack/plugins/fleet/common/types/models/agent.ts b/x-pack/plugins/fleet/common/types/models/agent.ts index 84636e380fd62..89b533c47341f 100644 --- a/x-pack/plugins/fleet/common/types/models/agent.ts +++ b/x-pack/plugins/fleet/common/types/models/agent.ts @@ -187,7 +187,7 @@ export interface AgentDiagnostics { name: string; createTime: string; filePath: string; - status: 'READY' | 'AWAITING_UPLOAD' | 'DELETED' | 'IN_PROGRESS' | 'FAILED'; + status: 'READY' | 'AWAITING_UPLOAD' | 'DELETED' | 'EXPIRED' | 'IN_PROGRESS' | 'FAILED'; actionId: string; error?: string; } diff --git a/x-pack/plugins/fleet/common/types/models/package_policy.ts b/x-pack/plugins/fleet/common/types/models/package_policy.ts index d7c21d3916188..08cff4870b27e 100644 --- a/x-pack/plugins/fleet/common/types/models/package_policy.ts +++ b/x-pack/plugins/fleet/common/types/models/package_policy.ts @@ -13,6 +13,7 @@ export interface PackagePolicyPackage { title: string; version: string; experimental_data_stream_features?: ExperimentalDataStreamFeature[]; + requires_root?: boolean; } export interface PackagePolicyConfigRecordEntry { diff --git a/x-pack/plugins/fleet/common/types/rest_spec/agent.ts b/x-pack/plugins/fleet/common/types/rest_spec/agent.ts index b175d336a8f23..bb69346bbdce4 100644 --- a/x-pack/plugins/fleet/common/types/rest_spec/agent.ts +++ b/x-pack/plugins/fleet/common/types/rest_spec/agent.ts @@ -54,6 +54,11 @@ export interface GetAgentUploadsResponse { items: AgentDiagnostics[]; } +export interface DeleteAgentUploadResponse { + id: string; + deleted: boolean; +} + export interface PostNewAgentActionRequest { body: { action: Omit; diff --git a/x-pack/plugins/fleet/public/applications/fleet/layouts/default/default.tsx b/x-pack/plugins/fleet/public/applications/fleet/layouts/default/default.tsx index fb51cf369684f..5c25b70f7b67c 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/layouts/default/default.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/layouts/default/default.tsx @@ -7,9 +7,11 @@ import React from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; +import { EuiCallOut, EuiLink } from '@elastic/eui'; +import { useDismissableTour } from '../../../../hooks/use_dismissable_tour'; import type { Section } from '../../sections'; -import { useLink, useConfig, useAuthz } from '../../hooks'; +import { useLink, useConfig, useAuthz, useStartServices } from '../../hooks'; import { WithHeaderLayout } from '../../../../layouts'; import { ExperimentalFeaturesService } from '../../services'; @@ -30,7 +32,10 @@ export const DefaultLayout: React.FunctionComponent = ({ const { getHref } = useLink(); const { agents } = useConfig(); const authz = useAuthz(); - const { agentTamperProtectionEnabled } = ExperimentalFeaturesService.get(); + const { agentTamperProtectionEnabled, subfeaturePrivileges } = ExperimentalFeaturesService.get(); + + const { docLinks } = useStartServices(); + const granularPrivilegesCallout = useDismissableTour('GRANULAR_PRIVILEGES'); const tabs = [ { @@ -109,8 +114,37 @@ export const DefaultLayout: React.FunctionComponent = ({ .map(({ isHidden, ...tab }) => tab); return ( - } rightColumn={rightColumn} tabs={tabs}> - {children} - + <> + {!subfeaturePrivileges || !authz.fleet.all || granularPrivilegesCallout.isHidden ? null : ( + + + + + + + ), + }} + /> + + } + /> + )} + } rightColumn={rightColumn} tabs={tabs}> + {children} + + ); }; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/confirm_deploy_modal.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/confirm_deploy_modal.tsx index 1198db3034dee..34b9ef59bd8c6 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/confirm_deploy_modal.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/confirm_deploy_modal.tsx @@ -11,13 +11,23 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import type { AgentPolicy } from '../../../types'; +import { UnprivilegedAgentsCallout } from '../create_package_policy_page/single_page_layout/confirm_modal'; export const ConfirmDeployAgentPolicyModal: React.FunctionComponent<{ onConfirm: () => void; onCancel: () => void; agentCount: number; agentPolicy: AgentPolicy; -}> = ({ onConfirm, onCancel, agentCount, agentPolicy }) => { + showUnprivilegedAgentsCallout?: boolean; + unprivilegedAgentsCount?: number; +}> = ({ + onConfirm, + onCancel, + agentCount, + agentPolicy, + showUnprivilegedAgentsCallout = false, + unprivilegedAgentsCount = 0, +}) => { return ( + {showUnprivilegedAgentsCallout && ( + <> + + + + )} = ( const [localIsManaged, setLocalIsManaged] = useState(props.isManaged); const [useLocalState, setUseLocalState] = useState(false); - const enrolledAgentIds = usePollingAgentCount(props.agentPolicy?.id || '', { + const { enrolledAgentIds } = usePollingAgentCount(props.agentPolicy?.id || '', { noLowerTimeLimit: true, pollImmediately: true, }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/page_steps/install_agent/install_agent_managed.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/page_steps/install_agent/install_agent_managed.tsx index 8419534a406f8..7b442a5af23a3 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/page_steps/install_agent/install_agent_managed.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/page_steps/install_agent/install_agent_managed.tsx @@ -21,6 +21,8 @@ import { ManualInstructions } from '../../../../../../../../../components/enroll import { KubernetesManifestApplyStep } from '../../../../../../../../../components/agent_enrollment_flyout/steps/run_k8s_apply_command_step'; +import { getRootIntegrations } from '../../../../../../../../../../common/services'; + import type { InstallAgentPageProps } from './types'; export const InstallElasticAgentManagedPageStep: React.FC = (props) => { @@ -80,6 +82,7 @@ export const InstallElasticAgentManagedPageStep: React.FC fullCopyButton: true, fleetServerHost, onCopy: () => setCommandCopied(true), + rootIntegrations: getRootIntegrations(agentPolicy?.package_policies ?? []), }), ]; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/page_steps/install_agent/install_agent_standalone.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/page_steps/install_agent/install_agent_standalone.tsx index f49aaefd65dd9..e2f92331759ac 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/page_steps/install_agent/install_agent_standalone.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/page_steps/install_agent/install_agent_standalone.tsx @@ -12,6 +12,7 @@ import { safeDump } from 'js-yaml'; import type { FullAgentPolicy } from '../../../../../../../../../../common/types/models/agent_policy'; import { API_VERSIONS } from '../../../../../../../../../../common/constants'; +import { getRootIntegrations } from '../../../../../../../../../../common/services'; import { AgentStandaloneBottomBar, StandaloneModeWarningCallout, @@ -112,6 +113,7 @@ export const InstallElasticAgentStandalonePageStep: React.FC setCommandCopied(true), + rootIntegrations: getRootIntegrations(agentPolicy?.package_policies ?? []), }), ]; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/confirm_modal.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/confirm_modal.tsx new file mode 100644 index 0000000000000..8ae069de21e55 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/confirm_modal.tsx @@ -0,0 +1,81 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiCallOut, EuiConfirmModal } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { i18n } from '@kbn/i18n'; + +export interface UnprivilegedConfirmModalProps { + onConfirm: () => void; + onCancel: () => void; + agentPolicyName: string; + unprivilegedAgentsCount: number; +} + +export const UnprivilegedConfirmModal: React.FC = ({ + onConfirm, + onCancel, + agentPolicyName, + unprivilegedAgentsCount, +}: UnprivilegedConfirmModalProps) => { + return ( + + } + onCancel={onCancel} + onConfirm={onConfirm} + cancelButtonText={ + + } + confirmButtonText={ + + } + buttonColor="warning" + > + + + ); +}; + +export const UnprivilegedAgentsCallout: React.FC<{ + agentPolicyName: string; + unprivilegedAgentsCount: number; +}> = ({ agentPolicyName, unprivilegedAgentsCount }) => { + return ( + + + + ); +}; 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 b256349f5d6b9..f7b46d95f1e67 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 @@ -31,7 +31,10 @@ import { PACKAGE_POLICY_SAVED_OBJECT_TYPE, SO_SEARCH_LIMIT, } from '../../../../../../../../common'; -import { getMaxPackageName } from '../../../../../../../../common/services'; +import { + getMaxPackageName, + isRootPrivilegesRequired, +} from '../../../../../../../../common/services'; import { useConfirmForceInstall } from '../../../../../../integrations/hooks'; import { validatePackagePolicy, validationHasErrors } from '../../services'; import type { PackagePolicyValidationResults } from '../../services'; @@ -266,6 +269,16 @@ export function useOnSubmit({ setFormState('CONFIRM'); return; } + if ( + packageInfo && + isRootPrivilegesRequired(packageInfo) && + (agentPolicy?.unprivileged_agents ?? 0) > 0 && + formState !== 'CONFIRM' && + formState !== 'CONFIRM_UNPRIVILEGED' + ) { + setFormState('CONFIRM_UNPRIVILEGED'); + return; + } let createdPolicy = overrideCreatedAgentPolicy; if (selectedPolicyTab === SelectedPolicyTab.NEW && !overrideCreatedAgentPolicy) { try { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.test.tsx index e8ef63a7bfdbc..28f8c380eb2eb 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.test.tsx @@ -37,14 +37,28 @@ jest.mock('../../../../hooks', () => { sendGetAgentStatus: jest.fn().mockResolvedValue({ data: { results: { total: 0 } } }), useGetAgentPolicies: jest.fn().mockReturnValue({ data: { - items: [{ id: 'agent-policy-1', name: 'Agent policy 1', namespace: 'default' }], + items: [ + { + id: 'agent-policy-1', + name: 'Agent policy 1', + namespace: 'default', + unprivileged_agents: 1, + }, + ], }, error: undefined, isLoading: false, resendRequest: jest.fn(), } as any), sendGetOneAgentPolicy: jest.fn().mockResolvedValue({ - data: { item: { id: 'agent-policy-1', name: 'Agent policy 1', namespace: 'default' } }, + data: { + item: { + id: 'agent-policy-1', + name: 'Agent policy 1', + namespace: 'default', + unprivileged_agents: 1, + }, + }, }), useGetPackageInfoByKeyQuery: jest.fn(), sendGetSettings: jest.fn().mockResolvedValue({ @@ -129,16 +143,9 @@ describe('when on the package policy create page', () => { /> )); - let mockPackageInfo: any; - - beforeEach(() => { - testRenderer = createFleetTestRendererMock(); - mockApiCalls(testRenderer.startServices.http); - testRenderer.mountHistory.push(createPageUrlPath); - jest.mocked(useStartServices().application.navigateToApp).mockReset(); - - mockPackageInfo = { + function getMockPackageInfo(requiresRoot?: boolean) { + return { data: { item: { name: 'nginx', @@ -193,12 +200,25 @@ describe('when on the package policy create page', () => { latestVersion: '1.3.0', keepPoliciesUpToDate: false, status: 'not_installed', + agent: { + privileges: { + root: requiresRoot, + }, + }, }, }, isLoading: false, }; + } - (useGetPackageInfoByKeyQuery as jest.Mock).mockReturnValue(mockPackageInfo); + beforeEach(() => { + testRenderer = createFleetTestRendererMock(); + mockApiCalls(testRenderer.startServices.http); + testRenderer.mountHistory.push(createPageUrlPath); + + jest.mocked(useStartServices().application.navigateToApp).mockReset(); + + (useGetPackageInfoByKeyQuery as jest.Mock).mockReturnValue(getMockPackageInfo()); }); describe('and Route state is provided via Fleet HashRouter', () => { @@ -280,6 +300,73 @@ describe('when on the package policy create page', () => { vars: undefined, }; + test('should show unprivileged warning modal on submit if conditions match', async () => { + (useGetPackageInfoByKeyQuery as jest.Mock).mockReturnValue(getMockPackageInfo(true)); + await act(async () => { + render('agent-policy-1'); + }); + + let saveBtn: HTMLElement; + + await waitFor(() => { + saveBtn = renderResult.getByText(/Save and continue/).closest('button')!; + expect(saveBtn).not.toBeDisabled(); + }); + + await act(async () => { + fireEvent.click(saveBtn); + }); + + await waitFor(() => { + expect( + renderResult.getByText('Unprivileged agents enrolled to the selected policy') + ).toBeInTheDocument(); + expect(renderResult.getByTestId('unprivilegedAgentsCallout').textContent).toContain( + 'This integration requires Elastic Agents to have root privileges. There is 1 agent running in an unprivileged mode using Agent policy 1. To ensure that all data required by the integration can be collected, re-enroll the agent using an account with root privileges.' + ); + }); + + await waitFor(() => { + saveBtn = renderResult.getByText(/Add integration/).closest('button')!; + }); + + await act(async () => { + fireEvent.click(saveBtn); + }); + + expect(sendCreatePackagePolicy as jest.MockedFunction).toHaveBeenCalledTimes(1); + }); + + test('should show unprivileged warning and agents modal on submit if conditions match', async () => { + (useGetPackageInfoByKeyQuery as jest.Mock).mockReturnValue(getMockPackageInfo(true)); + (sendGetAgentStatus as jest.MockedFunction).mockResolvedValueOnce({ + data: { results: { total: 1 } }, + }); + await act(async () => { + render('agent-policy-1'); + }); + + await act(async () => { + fireEvent.click(renderResult.getByText(/Save and continue/).closest('button')!); + }); + + await waitFor(() => { + expect(renderResult.getByText('This action will update 1 agent')).toBeInTheDocument(); + expect( + renderResult.getByText('Unprivileged agents enrolled to the selected policy') + ).toBeInTheDocument(); + expect(renderResult.getByTestId('unprivilegedAgentsCallout').textContent).toContain( + 'This integration requires Elastic Agents to have root privileges. There is 1 agent running in an unprivileged mode using Agent policy 1. To ensure that all data required by the integration can be collected, re-enroll the agent using an account with root privileges.' + ); + }); + + await act(async () => { + fireEvent.click(renderResult.getAllByText(/Save and deploy changes/)[1].closest('button')!); + }); + + expect(sendCreatePackagePolicy as jest.MockedFunction).toHaveBeenCalled(); + }); + test('should create package policy on submit when query param agent policy id is set', async () => { await act(async () => { render('agent-policy-1'); @@ -384,10 +471,10 @@ describe('when on the package policy create page', () => { test('should create agent policy without sys monitoring when new hosts is selected for system integration', async () => { (useGetPackageInfoByKeyQuery as jest.Mock).mockReturnValue({ - ...mockPackageInfo, + ...getMockPackageInfo(), data: { item: { - ...mockPackageInfo.data!.item, + ...getMockPackageInfo().data!.item, name: 'system', }, }, @@ -472,7 +559,7 @@ describe('when on the package policy create page', () => { expect(renderResult.getByText(/Save and continue/).closest('button')!).toBeDisabled(); }); - test('should not show modal if agent policy has agents', async () => { + test('should show modal if agent policy has agents', async () => { (sendGetAgentStatus as jest.MockedFunction).mockResolvedValueOnce({ data: { results: { total: 1 } }, }); 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 572b7a4136ea5..2184693e6623a 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 @@ -75,6 +75,7 @@ import { useDevToolsRequest, useOnSubmit, useSetupTechnology } from './hooks'; import { PostInstallCloudFormationModal } from './components/cloud_security_posture/post_install_cloud_formation_modal'; import { PostInstallGoogleCloudShellModal } from './components/cloud_security_posture/post_install_google_cloud_shell_modal'; import { PostInstallAzureArmTemplateModal } from './components/cloud_security_posture/post_install_azure_arm_template_modal'; +import { UnprivilegedConfirmModal } from './confirm_modal'; const StepsWithLessPadding = styled(EuiSteps)` .euiStep__content { @@ -436,6 +437,7 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({ /> ); } + return ( @@ -445,8 +447,22 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({ agentPolicy={agentPolicy} onConfirm={onSubmit} onCancel={() => setFormState('VALID')} + showUnprivilegedAgentsCallout={Boolean( + packageInfo && + isRootPrivilegesRequired(packageInfo) && + (agentPolicy?.unprivileged_agents ?? 0) > 0 + )} + unprivilegedAgentsCount={agentPolicy?.unprivileged_agents ?? 0} /> )} + {formState === 'CONFIRM_UNPRIVILEGED' && agentPolicy ? ( + setFormState('VALID')} + onConfirm={onSubmit} + unprivilegedAgentsCount={agentPolicy?.unprivileged_agents ?? 0} + agentPolicyName={agentPolicy?.name ?? ''} + /> + ) : null} {formState === 'SUBMITTED_NO_AGENTS' && agentPolicy && packageInfo && diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/types.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/types.ts index 1a203c8bf2e60..0d533597a60eb 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/types.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/types.ts @@ -19,6 +19,7 @@ export type PackagePolicyFormState = | 'VALID' | 'INVALID' | 'CONFIRM' + | 'CONFIRM_UNPRIVILEGED' | 'LOADING' | 'SUBMITTED' | 'SUBMITTED_NO_AGENTS' diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/header/right_content.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/header/right_content.tsx index 743dd5186d3b5..5dd391450b0cb 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/header/right_content.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/header/right_content.tsx @@ -19,6 +19,7 @@ import { EuiDescriptionListDescription, EuiLink, EuiToolTip, + EuiIconTip, } from '@elastic/eui'; import { useAuthz, useLink } from '../../../../../hooks'; @@ -26,6 +27,7 @@ import type { AgentPolicy } from '../../../../../types'; import { AgentPolicyActionMenu, LinkedAgentCount } from '../../../components'; import { AddAgentHelpPopover } from '../../../../../components'; import { FLEET_SERVER_PACKAGE } from '../../../../../../../../common/constants'; +import { getRootIntegrations } from '../../../../../../../../common/services'; export interface HeaderRightContentProps { isLoading: boolean; @@ -130,36 +132,55 @@ export const HeaderRightContent: React.FunctionComponent ) : ( - - - + + + + + + + + +
+ } + > + + +
+ {getRootIntegrations(agentPolicy.package_policies || []).length > 0 && + (agentPolicy.unprivileged_agents || 0) > 0 && ( + + + } /> - - - -
- } - > - - + )} + ), }, { isDivider: true }, diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/list_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/list_page/index.tsx index b96a2e75ec537..a2e0e6663e5cf 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/list_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/list_page/index.tsx @@ -16,6 +16,7 @@ import { EuiBasicTable, EuiLink, EuiToolTip, + EuiIconTip, } from '@elastic/eui'; import type { CriteriaWithPagination } from '@elastic/eui/src/components/basic_table/basic_table'; import { i18n } from '@kbn/i18n'; @@ -23,6 +24,7 @@ import { FormattedMessage, FormattedDate } from '@kbn/i18n-react'; import { useHistory } from 'react-router-dom'; import type { AgentPolicy } from '../../../types'; +import { getRootIntegrations } from '../../../../../../common/services'; import { AGENT_POLICY_SAVED_OBJECT_TYPE } from '../../../constants'; import { useAuthz, @@ -164,24 +166,45 @@ export const AgentPolicyListPage: React.FunctionComponent<{}> = () => { - {'('} - - } - > - - - {')'} + + } + > + + + ), + }} + /> + {getRootIntegrations(agentPolicy.package_policies || []).length > 0 && + (agentPolicy.unprivileged_agents || 0) > 0 && ( + + + } + /> + + )} ), }, diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_diagnostics/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_diagnostics/index.tsx index 1eaea92be9639..1bb7e1ee0ad00 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_diagnostics/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_diagnostics/index.tsx @@ -5,13 +5,12 @@ * 2.0. */ -import type { EuiTableFieldDataColumnType } from '@elastic/eui'; -import { EuiPortal } from '@elastic/eui'; -import { EuiToolTip } from '@elastic/eui'; +import type { EuiBasicTableColumn } from '@elastic/eui'; import { + EuiPortal, + EuiToolTip, EuiBasicTable, EuiButton, - EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiIcon, @@ -20,9 +19,10 @@ import { EuiText, EuiSkeletonText, formatDate, + EuiSpacer, + EuiSwitch, } from '@elastic/eui'; import React, { useCallback, useEffect, useState } from 'react'; -import styled from 'styled-components'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; @@ -31,18 +31,16 @@ import { MINIMUM_DIAGNOSTICS_AGENT_VERSION, } from '../../../../../../../../common/services'; -import { sendGetAgentUploads, useAuthz, useLink, useStartServices } from '../../../../../hooks'; +import { + sendGetAgentUploads, + useAuthz, + useLink, + useStartServices, + sendDeleteAgentUpload, +} from '../../../../../hooks'; import type { AgentDiagnostics, Agent } from '../../../../../../../../common/types/models'; import { AgentRequestDiagnosticsModal } from '../../../components/agent_request_diagnostics_modal'; -const FlexStartEuiFlexItem = styled(EuiFlexItem)` - align-self: flex-start; -`; - -const MarginedIcon = styled(EuiIcon)` - margin-right: 7px; -`; - export interface AgentDiagnosticsProps { agent: Agent; } @@ -52,7 +50,9 @@ export const AgentDiagnosticsTab: React.FunctionComponent const { notifications } = useStartServices(); const { getAbsolutePath } = useLink(); const [isLoading, setIsLoading] = useState(true); - const [diagnosticsEntries, setDiagnosticEntries] = useState([]); + const [isShowingExpiredEntries, setIsShowingExpiredEntries] = useState(false); + const [visibleDiagnosticsEntries, setVisibleDiagnosticEntries] = useState([]); + const [allDiagnosticsEntries, setAllDiagnosticEntries] = useState([]); const [prevDiagnosticsEntries, setPrevDiagnosticEntries] = useState([]); const [loadInterval, setLoadInterval] = useState(10000); const [isRequestDiagnosticsModalOpen, setIsRequestDiagnosticsModalOpen] = useState(false); @@ -68,7 +68,7 @@ export const AgentDiagnosticsTab: React.FunctionComponent throw new Error('No data'); } const entries = uploadsResponse.data.items; - setDiagnosticEntries(entries); + setAllDiagnosticEntries(entries); setIsLoading(false); // query faster if an action is in progress, for quicker feedback @@ -93,6 +93,31 @@ export const AgentDiagnosticsTab: React.FunctionComponent } }, [agent.id, notifications.toasts, setLoadInterval]); + const deleteFile = (fileId: string) => { + sendDeleteAgentUpload(fileId).then(({ data, error }) => { + if (error || data?.deleted === false) { + notifications.toasts.addError(error || new Error('Request returned `deleted: false`'), { + title: i18n.translate( + 'xpack.fleet.requestDiagnostics.errorDeletingUploadNotificationTitle', + { + defaultMessage: 'Error deleting diagnostics file', + } + ), + }); + } else { + notifications.toasts.addSuccess({ + title: i18n.translate( + 'xpack.fleet.requestDiagnostics.successDeletingUploadNotificationTitle', + { + defaultMessage: 'Diagnostics file deleted', + } + ), + }); + } + loadData(); + }); + }; + useEffect(() => { loadData(); const interval: ReturnType | null = setInterval(async () => { @@ -109,9 +134,9 @@ export const AgentDiagnosticsTab: React.FunctionComponent }, [loadData, loadInterval]); useEffect(() => { - setPrevDiagnosticEntries(diagnosticsEntries); + setPrevDiagnosticEntries(allDiagnosticsEntries); if (prevDiagnosticsEntries.length > 0) { - diagnosticsEntries + allDiagnosticsEntries .filter((newEntry) => { const oldEntry = prevDiagnosticsEntries.find((entry) => entry.id === newEntry.id); return newEntry.status === 'READY' && (!oldEntry || oldEntry?.status !== 'READY'); @@ -130,17 +155,26 @@ export const AgentDiagnosticsTab: React.FunctionComponent ); }); } - }, [prevDiagnosticsEntries, diagnosticsEntries, notifications.toasts]); + }, [prevDiagnosticsEntries, allDiagnosticsEntries, notifications.toasts]); - const errorIcon = ; - const getErrorMessage = (error?: string) => (error ? `Error: ${error}` : ''); + useEffect(() => { + if (isShowingExpiredEntries) { + setVisibleDiagnosticEntries(allDiagnosticsEntries); + } else { + setVisibleDiagnosticEntries( + allDiagnosticsEntries.filter((entry) => entry.status !== 'EXPIRED') + ); + } + }, [allDiagnosticsEntries, isShowingExpiredEntries]); - const columns: Array> = [ + const columns: Array> = [ { field: 'id', - name: 'File', + name: i18n.translate('xpack.fleet.requestDiagnostics.tableColumns.fileLabelText', { + defaultMessage: 'File', + }), render: (id: string) => { - const currentItem = diagnosticsEntries.find((item) => item.id === id); + const currentItem = allDiagnosticsEntries.find((item) => item.id === id); return currentItem?.status === 'READY' ? (   {currentItem?.name} @@ -155,45 +189,81 @@ export const AgentDiagnosticsTab: React.FunctionComponent ) : ( - {currentItem?.status ? ( - -

Diagnostics status: {currentItem?.status}

-

{getErrorMessage(currentItem?.error)}

- - } - > - {errorIcon} -
- ) : ( - errorIcon - )} -   - {currentItem?.name} + + {currentItem?.error ? ( + + + } + > + + + + ) : currentItem?.status ? ( + + + + + + ) : null} + {currentItem?.name} +
); }, }, { field: 'id', - name: 'Date', + name: i18n.translate('xpack.fleet.requestDiagnostics.tableColumns.dateLabelText', { + defaultMessage: 'Date', + }), dataType: 'date', render: (id: string) => { - const currentItem = diagnosticsEntries.find((item) => item.id === id); + const currentItem = allDiagnosticsEntries.find((item) => item.id === id); return ( - + {formatDate(currentItem?.createTime, 'lll')} ); }, }, + { + name: i18n.translate('xpack.fleet.requestDiagnostics.tableColumns.actionsLabelText', { + defaultMessage: 'Actions', + }), + width: '70px', + actions: [ + { + type: 'icon', + icon: 'trash', + color: 'danger', + name: i18n.translate('xpack.fleet.requestDiagnostics.tableColumns.deleteButtonText', { + defaultMessage: 'Delete', + }), + available: (item: AgentDiagnostics) => item.status === 'READY', + description: i18n.translate( + 'xpack.fleet.requestDiagnostics.tableColumns.deleteButtonDesc', + { + defaultMessage: 'Delete diagnostics file', + } + ), + onClick: (item: AgentDiagnostics) => { + deleteFile(item.id); + }, + }, + ], + }, ]; const requestDiagnosticsButton = ( { setIsRequestDiagnosticsModalOpen(true); }} @@ -215,29 +285,27 @@ export const AgentDiagnosticsTab: React.FunctionComponent agentCount={1} onClose={() => { setIsRequestDiagnosticsModalOpen(false); + loadData(); }} /> )} - - - - } - > - - - - + +

+ +

+
+ + + {isAgentRequestDiagnosticsSupported(agent) ? ( requestDiagnosticsButton ) : ( @@ -253,15 +321,27 @@ export const AgentDiagnosticsTab: React.FunctionComponent {requestDiagnosticsButton} )} -
- - {isLoading ? ( - - ) : ( - items={diagnosticsEntries} columns={columns} /> - )} + + + + } + checked={isShowingExpiredEntries} + onChange={(e) => setIsShowingExpiredEntries(e.target.checked)} + />
+ + + {isLoading ? ( + + ) : ( + items={visibleDiagnosticsEntries} columns={columns} /> + )} ); }; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_status_filter.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_status_filter.test.tsx index d840ea4a74f87..5da6a4e8bf72a 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_status_filter.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_status_filter.test.tsx @@ -13,7 +13,7 @@ import { AgentStatusFilter } from './agent_status_filter'; const PARTIAL_TOUR_TEXT = 'Some agents have become inactive and have been hidden'; const mockStorage: Record = {}; -jest.mock('../../../../../../hooks', () => { +jest.mock('../../../../../../hooks/use_core', () => { return { useStartServices: jest.fn(() => ({ uiSettings: { @@ -81,14 +81,13 @@ describe('AgentStatusFilter', () => { it('Should not show tour if previously been dismissed', async () => { mockStorage['fleet.inactiveAgentsTour'] = { active: false }; - const { getByText } = renderComponent({ + const { queryByText } = renderComponent({ selectedStatus: [], onSelectedStatusChange: () => {}, totalInactiveAgents: 999, }); - await act(async () => { - expect(getByText(PARTIAL_TOUR_TEXT, { exact: false })).not.toBeVisible(); + expect(queryByText(PARTIAL_TOUR_TEXT, { exact: false })).toBeNull(); }); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_status_filter.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_status_filter.tsx index be9098f2e7916..3f1790ec11979 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_status_filter.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_status_filter.tsx @@ -16,12 +16,15 @@ import { EuiTourStep, EuiLink, } from '@elastic/eui'; + import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import styled from 'styled-components'; -import { useInactiveAgentsCalloutHasBeenDismissed, useLastSeenInactiveAgentsCount } from '../hooks'; +import { useDismissableTour } from '../../../../../../hooks/use_dismissable_tour'; + +import { useLastSeenInactiveAgentsCount } from '../hooks'; const statusFilters = [ { @@ -122,8 +125,8 @@ export const AgentStatusFilter: React.FC<{ } = props; const [lastSeenInactiveAgentsCount, setLastSeenInactiveAgentsCount] = useLastSeenInactiveAgentsCount(); - const [inactiveAgentsCalloutHasBeenDismissed, setInactiveAgentsCalloutHasBeenDismissed] = - useInactiveAgentsCalloutHasBeenDismissed(); + const { isHidden: inactiveAgentsCalloutHasBeenDismissed, dismiss: dismissInactiveAgentsCallout } = + useDismissableTour('INACTIVE_AGENTS'); const newlyInactiveAgentsCount = useMemo(() => { const newVal = totalInactiveAgents - lastSeenInactiveAgentsCount; @@ -159,7 +162,7 @@ export const AgentStatusFilter: React.FC<{ const updateIsStatusFilterOpen = (isOpen: boolean) => { if (isOpen && newlyInactiveAgentsCount > 0 && !inactiveAgentsCalloutHasBeenDismissed) { - setInactiveAgentsCalloutHasBeenDismissed(true); + dismissInactiveAgentsCallout(); } setIsStatusFilterOpen(isOpen); @@ -206,7 +209,7 @@ export const AgentStatusFilter: React.FC<{ return ( 0 && !inactiveAgentsCalloutHasBeenDismissed} - setInactiveAgentsCalloutHasBeenDismissed={setInactiveAgentsCalloutHasBeenDismissed} + setInactiveAgentsCalloutHasBeenDismissed={dismissInactiveAgentsCallout} > void] => { - const { uiSettings, storage } = useStartServices(); - - const [inactiveAgentsCalloutHasBeenDismissed, setInactiveAgentsCalloutHasBeenDismissed] = - useState(false); - - useEffect(() => { - setInactiveAgentsCalloutHasBeenDismissed( - uiSettings.get('hideAnnouncements', false) || - ( - storage.get(TOUR_STORAGE_KEYS.INACTIVE_AGENTS) as - | TOUR_STORAGE_CONFIG['INACTIVE_AGENTS'] - | undefined - )?.active === false - ); - }, [storage, uiSettings]); - - const updateInactiveAgentsCalloutHasBeenDismissed = (newValue: boolean) => { - storage.set(TOUR_STORAGE_KEYS.INACTIVE_AGENTS, { - active: false, - } as TOUR_STORAGE_CONFIG['INACTIVE_AGENTS']); - setInactiveAgentsCalloutHasBeenDismissed(newValue); - }; - - return [inactiveAgentsCalloutHasBeenDismissed, updateInactiveAgentsCalloutHasBeenDismissed]; -}; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_request_diagnostics_modal/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_request_diagnostics_modal/index.tsx index 82bf1f1b31874..9ea94aaeb134a 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_request_diagnostics_modal/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_request_diagnostics_modal/index.tsx @@ -125,7 +125,7 @@ export const AgentRequestDiagnosticsModal: React.FunctionComponent = ({

diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/debug/components/saved_object_debugger.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/debug/components/saved_object_debugger.tsx index 021608e4ef656..40f0c8e70a59b 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/debug/components/saved_object_debugger.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/debug/components/saved_object_debugger.tsx @@ -29,6 +29,7 @@ import { PACKAGES_SAVED_OBJECT_TYPE, DOWNLOAD_SOURCE_SAVED_OBJECT_TYPE, FLEET_SERVER_HOST_SAVED_OBJECT_TYPE, + INGEST_SAVED_OBJECT_INDEX, } from '../../../../../../common/constants'; import { CodeBlock } from './code_block'; @@ -36,7 +37,7 @@ import { SavedObjectNamesCombo } from './saved_object_names_combo'; const fetchSavedObjects = async (type?: string, name?: string) => { if (!type || !name) return; - const path = `/.kibana/_search`; + const path = `/${INGEST_SAVED_OBJECT_INDEX}/_search`; const body = { query: { bool: { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/debug/components/saved_object_names_combo.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/debug/components/saved_object_names_combo.tsx index aa9d7cb011e83..356d591fa2bf6 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/debug/components/saved_object_names_combo.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/debug/components/saved_object_names_combo.tsx @@ -12,9 +12,10 @@ import { EuiComboBox } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { sendRequest } from '../../../hooks'; +import { INGEST_SAVED_OBJECT_INDEX } from '../../../../../../common/constants'; const fetchSavedObjectNames = async (type: string) => { - const path = `/.kibana/_search`; + const path = `/${INGEST_SAVED_OBJECT_INDEX}/_search`; const body = { size: 0, query: { diff --git a/x-pack/plugins/fleet/public/components/add_agent_help_popover.tsx b/x-pack/plugins/fleet/public/components/add_agent_help_popover.tsx index 51cc95ffe4620..3c10a3b98a724 100644 --- a/x-pack/plugins/fleet/public/components/add_agent_help_popover.tsx +++ b/x-pack/plugins/fleet/public/components/add_agent_help_popover.tsx @@ -5,7 +5,7 @@ * 2.0. */ import type { ReactElement } from 'react'; -import React, { useMemo } from 'react'; +import React from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -15,9 +15,8 @@ import { useTheme } from 'styled-components'; import type { EuiTheme } from '@kbn/kibana-react-plugin/common'; -import type { TOUR_STORAGE_CONFIG } from '../constants'; -import { TOUR_STORAGE_KEYS } from '../constants'; import { useStartServices } from '../hooks'; +import { useDismissableTour } from '../hooks/use_dismissable_tour'; export const AddAgentHelpPopover = ({ button, @@ -30,31 +29,16 @@ export const AddAgentHelpPopover = ({ offset?: number; closePopover: NoArgCallback; }) => { - const { docLinks, uiSettings, storage } = useStartServices(); + const { docLinks } = useStartServices(); const theme = useTheme() as EuiTheme; const optionalProps: { offset?: number } = {}; - const hideAddAgentTour: boolean = useMemo(() => { - return ( - uiSettings.get('hideAnnouncements', false) || - ( - storage.get(TOUR_STORAGE_KEYS.ADD_AGENT_POPOVER) as - | TOUR_STORAGE_CONFIG['ADD_AGENT_POPOVER'] - | undefined - )?.active === false - ); - }, [storage, uiSettings]); - - const onFinish = () => { - storage.set(TOUR_STORAGE_KEYS.ADD_AGENT_POPOVER, { - active: false, - } as TOUR_STORAGE_CONFIG['ADD_AGENT_POPOVER']); - }; + const addAgentTour = useDismissableTour('ADD_AGENT_POPOVER'); if (offset !== undefined) { optionalProps.offset = offset; // offset being present in props sets it to 0 so only add if specified } - return hideAddAgentTour ? ( + return addAgentTour.isHidden ? ( button ) : ( { - onFinish(); + addAgentTour.dismiss(); closePopover(); }} > diff --git a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/confirm_agent_enrollment.tsx b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/confirm_agent_enrollment.tsx index 342f5f8f73249..53448aefd44c6 100644 --- a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/confirm_agent_enrollment.tsx +++ b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/confirm_agent_enrollment.tsx @@ -41,7 +41,10 @@ const POLLING_INTERVAL_MS = 5 * 1000; // 5 sec * @param policyId * @returns agentIds */ -export const usePollingAgentCount = (policyId: string, opts?: UsePollingAgentCountOptions) => { +export const usePollingAgentCount = ( + policyId: string, + opts?: UsePollingAgentCountOptions +): { enrolledAgentIds: string[] } => { const [agentIds, setAgentIds] = useState([]); const [didPollInitially, setDidPollInitially] = useState(false); const timeout = useRef(undefined); @@ -89,7 +92,7 @@ export const usePollingAgentCount = (policyId: string, opts?: UsePollingAgentCou isAborted = true; }; }, [agentIds, policyId, kuery, getNewAgentIds]); - return agentIds; + return { enrolledAgentIds: agentIds }; }; export const ConfirmAgentEnrollment: React.FunctionComponent = ({ diff --git a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/agent_enrollment_confirmation_step.tsx b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/agent_enrollment_confirmation_step.tsx index fc2ee7d131baf..761b662917d46 100644 --- a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/agent_enrollment_confirmation_step.tsx +++ b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/agent_enrollment_confirmation_step.tsx @@ -65,19 +65,22 @@ export const AgentEnrollmentConfirmationStep = ({ : i18n.translate('xpack.fleet.agentEnrollment.stepAgentEnrollmentConfirmation', { defaultMessage: 'Confirm agent enrollment', }), - children: - !!isComplete || poll ? ( - - ) : ( - - ), + children: ( + <> + {!!isComplete || poll ? ( + + ) : ( + + )} + + ), status: !isComplete ? 'incomplete' : 'complete', }; }; diff --git a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/compute_steps.tsx b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/compute_steps.tsx index 7cbe8125fcf38..615c6399b202f 100644 --- a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/compute_steps.tsx +++ b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/compute_steps.tsx @@ -14,6 +14,7 @@ import type { EuiContainedStepProps } from '@elastic/eui/src/components/steps/st import type { FullAgentPolicy } from '../../../../common/types/models/agent_policy'; import { API_VERSIONS } from '../../../../common/constants'; +import { getRootIntegrations } from '../../../../common/services'; import { fullAgentPolicyToYaml, agentPolicyRouteService } from '../../../services'; import { getGcpIntegrationDetailsFromAgentPolicy } from '../../cloud_security_posture/services'; @@ -168,6 +169,7 @@ export const StandaloneSteps: React.FunctionComponent = ({ installCommand: standaloneInstallCommands, isK8s, cloudSecurityIntegration, + rootIntegrations: getRootIntegrations(selectedPolicy?.package_policies ?? []), }) ); @@ -225,7 +227,7 @@ export const ManagedSteps: React.FunctionComponent = ({ const apiKeyData = apiKey?.data; const enrollToken = apiKey.data ? apiKey.data.item.api_key : ''; - const enrolledAgentIds = usePollingAgentCount(selectedPolicy?.id || ''); + const { enrolledAgentIds } = usePollingAgentCount(selectedPolicy?.id || ''); const agentVersion = useAgentVersion(); @@ -309,6 +311,7 @@ export const ManagedSteps: React.FunctionComponent = ({ cloudSecurityIntegration, fleetServerHost, enrollToken, + rootIntegrations: getRootIntegrations(selectedPolicy?.package_policies ?? []), }) ); } diff --git a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/install_managed_agent_step.tsx b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/install_managed_agent_step.tsx index 2a9c0536f3389..566d73aff7fc9 100644 --- a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/install_managed_agent_step.tsx +++ b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/install_managed_agent_step.tsx @@ -29,6 +29,7 @@ export const InstallManagedAgentStep = ({ isComplete, fullCopyButton, onCopy, + rootIntegrations, }: { selectedApiKeyId?: string; apiKeyData?: GetOneEnrollmentAPIKeyResponse | null; @@ -40,6 +41,7 @@ export const InstallManagedAgentStep = ({ isComplete?: boolean; fullCopyButton?: boolean; onCopy?: () => void; + rootIntegrations?: Array<{ name: string; title: string }>; }): EuiContainedStepProps => { const nonCompleteStatus = selectedApiKeyId ? undefined : 'disabled'; const status = isComplete ? 'complete' : nonCompleteStatus; @@ -58,6 +60,7 @@ export const InstallManagedAgentStep = ({ onCopy={onCopy} fullCopyButton={fullCopyButton} fleetServerHost={fleetServerHost} + rootIntegrations={rootIntegrations} /> ) : ( diff --git a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/install_standalone_agent_step.tsx b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/install_standalone_agent_step.tsx index 90ed25225b608..2e11cc165d4f7 100644 --- a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/install_standalone_agent_step.tsx +++ b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/install_standalone_agent_step.tsx @@ -23,6 +23,7 @@ export const InstallStandaloneAgentStep = ({ isComplete, fullCopyButton, onCopy, + rootIntegrations, }: { installCommand: CommandsByPlatform; isK8s?: K8sMode; @@ -30,6 +31,7 @@ export const InstallStandaloneAgentStep = ({ isComplete?: boolean; fullCopyButton?: boolean; onCopy?: () => void; + rootIntegrations?: Array<{ name: string; title: string }>; }): EuiContainedStepProps => { return { title: i18n.translate('xpack.fleet.agentEnrollment.stepEnrollAndRunAgentTitle', { @@ -43,6 +45,7 @@ export const InstallStandaloneAgentStep = ({ onCopy={onCopy} fullCopyButton={fullCopyButton} isManaged={false} + rootIntegrations={rootIntegrations} /> ), status: isComplete ? 'complete' : undefined, diff --git a/x-pack/plugins/fleet/public/components/enrollment_instructions/install_section.tsx b/x-pack/plugins/fleet/public/components/enrollment_instructions/install_section.tsx index 44a251fefd7bc..372f81ca47f96 100644 --- a/x-pack/plugins/fleet/public/components/enrollment_instructions/install_section.tsx +++ b/x-pack/plugins/fleet/public/components/enrollment_instructions/install_section.tsx @@ -14,6 +14,8 @@ import { InstallationMessage } from '../agent_enrollment_flyout/installation_mes import type { K8sMode, CloudSecurityIntegration } from '../agent_enrollment_flyout/types'; import { PlatformSelector } from '../platform_selector'; +import { RootPrivilegesCallout } from './root_privileges_callout'; + interface Props { installCommand: CommandsByPlatform; isK8s: K8sMode | undefined; @@ -23,6 +25,7 @@ interface Props { fullCopyButton?: boolean; isManaged?: boolean; onCopy?: () => void; + rootIntegrations?: Array<{ name: string; title: string }>; } export const InstallSection: React.FunctionComponent = ({ @@ -34,10 +37,12 @@ export const InstallSection: React.FunctionComponent = ({ fullCopyButton = false, isManaged = true, onCopy, + rootIntegrations, }) => { return ( <> + { + function render(rootIntegrations?: Array<{ name: string; title: string }>) { + cleanup(); + const renderer = createFleetTestRendererMock(); + const results = renderer.render(); + + return results; + } + + it('should render callout requiring root privileges', async () => { + const renderResult = render([{ name: 'auditd_manager', title: 'Auditd Manager' }]); + + await waitFor(() => { + expect(renderResult.getByText('Root privileges required')).toBeInTheDocument(); + expect(renderResult.getByTestId('rootPrivilegesCallout').textContent).toContain( + 'This agent policy contains the following integrations that require Elastic Agents to have root privileges. To ensure that all data required by the integrations can be collected, enroll the agents using an account with root privileges.' + ); + expect(renderResult.getByText('Auditd Manager')).toBeInTheDocument(); + }); + }); +}); diff --git a/x-pack/plugins/fleet/public/components/enrollment_instructions/root_privileges_callout.tsx b/x-pack/plugins/fleet/public/components/enrollment_instructions/root_privileges_callout.tsx new file mode 100644 index 0000000000000..3c115a78567af --- /dev/null +++ b/x-pack/plugins/fleet/public/components/enrollment_instructions/root_privileges_callout.tsx @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiCallOut, EuiSpacer } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; + +export const RootPrivilegesCallout: React.FC<{ + rootIntegrations?: Array<{ name: string; title: string }>; +}> = ({ rootIntegrations = [] }) => { + return rootIntegrations.length > 0 ? ( + <> + + +

    + {rootIntegrations.map((item) => ( +
  • {item.title}
  • + ))} +
+ + + + ) : null; +}; diff --git a/x-pack/plugins/fleet/public/constants/index.ts b/x-pack/plugins/fleet/public/constants/index.ts index ae14fae94627c..0af765a9912a6 100644 --- a/x-pack/plugins/fleet/public/constants/index.ts +++ b/x-pack/plugins/fleet/public/constants/index.ts @@ -48,16 +48,15 @@ export const TOUR_STORAGE_KEYS = { AGENT_ACTIVITY: 'fleet.agentActivityTour', ADD_AGENT_POPOVER: 'fleet.addAgentPopoverTour', INACTIVE_AGENTS: 'fleet.inactiveAgentsTour', + GRANULAR_PRIVILEGES: 'fleet.granularPrivileges', }; -export interface TOUR_STORAGE_CONFIG { - AGENT_ACTIVITY: { - active: boolean; - }; - ADD_AGENT_POPOVER: { - active: boolean; - }; - INACTIVE_AGENTS: { - active: boolean; - }; +export interface TourConfig { + active: boolean; } + +export type TourKey = keyof typeof TOUR_STORAGE_KEYS; + +export type TOUR_STORAGE_CONFIG = { + [k in TourKey]: TourConfig; +}; diff --git a/x-pack/plugins/fleet/public/hooks/use_dismissable_tour.test.ts b/x-pack/plugins/fleet/public/hooks/use_dismissable_tour.test.ts new file mode 100644 index 0000000000000..394699fc3f34f --- /dev/null +++ b/x-pack/plugins/fleet/public/hooks/use_dismissable_tour.test.ts @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { renderHook, act } from '@testing-library/react-hooks'; + +import { TOUR_STORAGE_KEYS } from '../constants'; +import { createStartServices } from '../mock'; + +import { useStartServices } from './use_core'; +import { useDismissableTour } from './use_dismissable_tour'; + +jest.mock('./use_core'); + +describe('useDismissableTour', () => { + let startServices: ReturnType; + beforeEach(() => { + startServices = createStartServices('/app/fleet'); + jest.mocked(useStartServices).mockReturnValue(startServices); + }); + it('should display the tour by default', () => { + const res = renderHook(() => useDismissableTour('GRANULAR_PRIVILEGES')); + + expect(res.result.current.isHidden).toBe(false); + }); + + it('should allow to dismiss the tour', () => { + const res = renderHook(() => useDismissableTour('GRANULAR_PRIVILEGES')); + expect(res.result.current.isHidden).toBe(false); + + act(() => res.result.current.dismiss()); + + expect(res.result.current.isHidden).toBe(true); + const storageValue = startServices.storage.get(TOUR_STORAGE_KEYS.GRANULAR_PRIVILEGES); + expect(storageValue).toBeDefined(); + expect(storageValue.active).toEqual(false); + }); + + it('should not display the tour if hideAnnouncements:true', () => { + jest.mocked(startServices.uiSettings.get).mockReturnValue(true); + const res = renderHook(() => useDismissableTour('GRANULAR_PRIVILEGES')); + + expect(res.result.current.isHidden).toBe(true); + }); + + it('should not display the tour if it is already dismissed', () => { + startServices.storage.set(TOUR_STORAGE_KEYS.GRANULAR_PRIVILEGES, { + active: false, + }); + const res = renderHook(() => useDismissableTour('GRANULAR_PRIVILEGES')); + + expect(res.result.current.isHidden).toBe(true); + }); +}); diff --git a/x-pack/plugins/fleet/public/hooks/use_dismissable_tour.ts b/x-pack/plugins/fleet/public/hooks/use_dismissable_tour.ts new file mode 100644 index 0000000000000..837557ba02730 --- /dev/null +++ b/x-pack/plugins/fleet/public/hooks/use_dismissable_tour.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { type TourKey, type TourConfig, TOUR_STORAGE_KEYS } from '../constants'; + +import { useStartServices } from './use_core'; + +export function useDismissableTour(tourKey: TourKey) { + const { storage, uiSettings } = useStartServices(); + + const defaultValue = + uiSettings.get('hideAnnouncements', false) || + (storage.get(TOUR_STORAGE_KEYS[tourKey]) as TourConfig | undefined)?.active === false; + + const [isHidden, setIsHidden] = React.useState(defaultValue); + + const dismiss = React.useCallback(() => { + setIsHidden(true); + storage.set(TOUR_STORAGE_KEYS[tourKey], { + active: false, + }); + }, [tourKey, storage]); + + return { + isHidden, + dismiss, + }; +} diff --git a/x-pack/plugins/fleet/public/hooks/use_request/agents.ts b/x-pack/plugins/fleet/public/hooks/use_request/agents.ts index 7b9f8600dcd69..236c470cd15b7 100644 --- a/x-pack/plugins/fleet/public/hooks/use_request/agents.ts +++ b/x-pack/plugins/fleet/public/hooks/use_request/agents.ts @@ -17,6 +17,7 @@ import type { PostRequestBulkDiagnosticsRequest, PostRequestDiagnosticsRequest, PostRequestDiagnosticsResponse, + DeleteAgentUploadResponse, UpdateAgentRequest, } from '../../../common/types'; @@ -244,6 +245,15 @@ export function sendGetAgentUploads(agentId: string, options?: RequestOptions) { }); } +export function sendDeleteAgentUpload(fileId: string, options?: RequestOptions) { + return sendRequest({ + path: agentRouteService.getAgentFileDeletePath(fileId), + method: 'delete', + version: API_VERSIONS.public.v1, + ...options, + }); +} + export const useGetAgentUploads = (agentId: string, options?: RequestOptions) => { return useRequest({ path: agentRouteService.getListAgentUploads(agentId), diff --git a/x-pack/plugins/fleet/server/collectors/fleet_server_collector.ts b/x-pack/plugins/fleet/server/collectors/fleet_server_collector.ts index c67ed667f3665..4369a30a4a98f 100644 --- a/x-pack/plugins/fleet/server/collectors/fleet_server_collector.ts +++ b/x-pack/plugins/fleet/server/collectors/fleet_server_collector.ts @@ -20,6 +20,8 @@ const DEFAULT_USAGE = { unhealthy: 0, offline: 0, updating: 0, + inactive: 0, + unenrolled: 0, num_host_urls: 0, }; @@ -29,6 +31,8 @@ export interface FleetServerUsage { unhealthy: number; offline: number; updating: number; + inactive: number; + unenrolled: number; total_all_statuses: number; num_host_urls: number; } @@ -68,14 +72,15 @@ export const getFleetServerUsage = async ( return DEFAULT_USAGE; } - const { total, inactive, online, error, updating, offline } = await getAgentStatusForAgentPolicy( - esClient, - soClient, - undefined, - Array.from(policyIds) - .map((policyId) => `(policy_id:"${policyId}")`) - .join(' or ') - ); + const { total, inactive, online, error, updating, offline, unenrolled } = + await getAgentStatusForAgentPolicy( + esClient, + soClient, + undefined, + Array.from(policyIds) + .map((policyId) => `(policy_id:"${policyId}")`) + .join(' or ') + ); return { total_enrolled: total, @@ -83,6 +88,8 @@ export const getFleetServerUsage = async ( unhealthy: error, offline, updating, + inactive, + unenrolled, total_all_statuses: total + inactive, num_host_urls: numHostsUrls, }; diff --git a/x-pack/plugins/fleet/server/collectors/register.ts b/x-pack/plugins/fleet/server/collectors/register.ts index b350723f62696..398eb9e5b5ca3 100644 --- a/x-pack/plugins/fleet/server/collectors/register.ts +++ b/x-pack/plugins/fleet/server/collectors/register.ts @@ -199,6 +199,18 @@ export function registerFleetUsageCollector( description: 'The total number of enrolled Fleet Server agents currently offline', }, }, + inactive: { + type: 'long', + _meta: { + description: 'The total number of enrolled Fleet Server agents currently inactive', + }, + }, + unenrolled: { + type: 'long', + _meta: { + description: 'The total number of unenrolled Fleet Server agents', + }, + }, num_host_urls: { type: 'long', _meta: { diff --git a/x-pack/plugins/fleet/server/constants/index.ts b/x-pack/plugins/fleet/server/constants/index.ts index 55ad1f9881a8a..bf5179546c3f0 100644 --- a/x-pack/plugins/fleet/server/constants/index.ts +++ b/x-pack/plugins/fleet/server/constants/index.ts @@ -19,6 +19,7 @@ export { UNPRIVILEGED_AGENT_KUERY, PRIVILEGED_AGENT_KUERY, MAX_TIME_COMPLETE_INSTALL, + REQUEST_DIAGNOSTICS_TIMEOUT_MS, // Routes LIMITED_CONCURRENCY_ROUTE_TAG, PLUGIN_ID, diff --git a/x-pack/plugins/fleet/server/integration_tests/fleet_usage_telemetry.test.ts b/x-pack/plugins/fleet/server/integration_tests/fleet_usage_telemetry.test.ts index dbce3c7f8b435..30af71092594e 100644 --- a/x-pack/plugins/fleet/server/integration_tests/fleet_usage_telemetry.test.ts +++ b/x-pack/plugins/fleet/server/integration_tests/fleet_usage_telemetry.test.ts @@ -481,6 +481,8 @@ describe('fleet usage telemetry', () => { unhealthy: 0, offline: 0, updating: 0, + inactive: 0, + unenrolled: 0, num_host_urls: 0, }, packages: [], diff --git a/x-pack/plugins/fleet/server/routes/agent/handlers.ts b/x-pack/plugins/fleet/server/routes/agent/handlers.ts index f4d87b9193899..b292cc2f88c33 100644 --- a/x-pack/plugins/fleet/server/routes/agent/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/agent/handlers.ts @@ -35,6 +35,7 @@ import type { PostBulkUpdateAgentTagsRequestSchema, GetActionStatusRequestSchema, GetAgentUploadFileRequestSchema, + DeleteAgentUploadFileRequestSchema, PostRetrieveAgentsByActionsRequestSchema, } from '../../types'; import { defaultFleetErrorHandler } from '../../errors'; @@ -429,3 +430,17 @@ export const getAgentUploadFileHandler: RequestHandler< return defaultFleetErrorHandler({ error, response }); } }; + +export const deleteAgentUploadFileHandler: RequestHandler< + TypeOf +> = async (context, request, response) => { + const coreContext = await context.core; + const esClient = coreContext.elasticsearch.client.asInternalUser; + try { + const resp = await AgentService.deleteAgentUploadFile(esClient, request.params.fileId); + + return response.ok({ body: resp }); + } catch (error) { + return defaultFleetErrorHandler({ error, response }); + } +}; diff --git a/x-pack/plugins/fleet/server/routes/agent/index.ts b/x-pack/plugins/fleet/server/routes/agent/index.ts index 212397a5c3a99..640a9f69ed4d6 100644 --- a/x-pack/plugins/fleet/server/routes/agent/index.ts +++ b/x-pack/plugins/fleet/server/routes/agent/index.ts @@ -34,6 +34,7 @@ import { ListAgentUploadsRequestSchema, GetAgentUploadFileRequestSchema, PostRetrieveAgentsByActionsRequestSchema, + DeleteAgentUploadFileRequestSchema, } from '../../types'; import * as AgentService from '../../services/agents'; import type { FleetConfigType } from '../..'; @@ -57,6 +58,7 @@ import { getActionStatusHandler, getAgentUploadsHandler, getAgentUploadFileHandler, + deleteAgentUploadFileHandler, postAgentsReassignHandler, postRetrieveAgentsByActionsHandler, } from './handlers'; @@ -332,6 +334,21 @@ export const registerAPIRoutes = (router: FleetAuthzRouter, config: FleetConfigT getAgentUploadFileHandler ); + router.versioned + .delete({ + path: AGENT_API_ROUTES.DELETE_UPLOAD_FILE_PATTERN, + fleetAuthz: { + fleet: { readAgents: true }, + }, + }) + .addVersion( + { + version: API_VERSIONS.public.v1, + validate: { request: DeleteAgentUploadFileRequestSchema }, + }, + deleteAgentUploadFileHandler + ); + // Get agent status for policy router.versioned .get({ diff --git a/x-pack/plugins/fleet/server/saved_objects/index.ts b/x-pack/plugins/fleet/server/saved_objects/index.ts index f74366d924c96..457711b2646e7 100644 --- a/x-pack/plugins/fleet/server/saved_objects/index.ts +++ b/x-pack/plugins/fleet/server/saved_objects/index.ts @@ -86,6 +86,7 @@ import { } from './migrations/security_solution/to_v8_11_0_2'; import { settingsV1 } from './model_versions/v1'; import { packagePolicyV10OnWriteScanFix } from './model_versions/security_solution'; +import { migratePackagePolicySetRequiresRootToV8150 } from './migrations/to_v8_15_0'; /* * Saved object types and mappings @@ -433,6 +434,7 @@ export const getSavedObjectTypes = ( name: { type: 'keyword' }, title: { type: 'keyword' }, version: { type: 'keyword' }, + requires_root: { type: 'boolean' }, }, }, elasticsearch: { @@ -549,6 +551,20 @@ export const getSavedObjectTypes = ( }, ], }, + '11': { + changes: [ + { + type: 'mappings_addition', + addedMappings: { + package: { properties: { requires_root: { type: 'boolean' } } }, + }, + }, + { + type: 'data_backfill', + backfillFn: migratePackagePolicySetRequiresRootToV8150, + }, + ], + }, }, migrations: { '7.10.0': migratePackagePolicyToV7100, diff --git a/x-pack/plugins/fleet/server/saved_objects/migrations/to_v8_15_0.test.ts b/x-pack/plugins/fleet/server/saved_objects/migrations/to_v8_15_0.test.ts new file mode 100644 index 0000000000000..656dfaddc75d6 --- /dev/null +++ b/x-pack/plugins/fleet/server/saved_objects/migrations/to_v8_15_0.test.ts @@ -0,0 +1,85 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + createModelVersionTestMigrator, + type ModelVersionTestMigrator, +} from '@kbn/core-test-helpers-model-versions'; + +import type { SavedObject } from '@kbn/core-saved-objects-server'; + +import type { PackagePolicy } from '../../../common'; +import { PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '../../../common'; +import { getSavedObjectTypes } from '..'; + +const getPolicyDoc = (packageName: string): SavedObject => { + return { + id: 'mock-saved-object-id', + attributes: { + name: 'Some Policy Name', + package: { + name: packageName, + title: '', + version: '', + }, + id: 'package-policy-1', + policy_id: '', + enabled: true, + namespace: '', + revision: 0, + updated_at: '', + updated_by: '', + created_at: '', + created_by: '', + inputs: [], + }, + type: PACKAGE_POLICY_SAVED_OBJECT_TYPE, + references: [], + }; +}; + +describe('8.15.0 Requires Root Package Policy migration', () => { + let migrator: ModelVersionTestMigrator; + + beforeEach(() => { + migrator = createModelVersionTestMigrator({ + type: getSavedObjectTypes()[PACKAGE_POLICY_SAVED_OBJECT_TYPE], + }); + }); + + describe('backfilling `requires_root`', () => { + it('should backfill `requires_root` field as `true` for `endpoint` package on Kibana update', () => { + const migratedPolicyConfigSO = migrator.migrate({ + document: getPolicyDoc('endpoint'), + fromVersion: 10, + toVersion: 11, + }); + + expect(migratedPolicyConfigSO.attributes.package?.requires_root).toBe(true); + }); + + it('should backfill `requires_root` field as `true` for `auditd_manager` package on Kibana update', () => { + const migratedPolicyConfigSO = migrator.migrate({ + document: getPolicyDoc('auditd_manager'), + fromVersion: 10, + toVersion: 11, + }); + + expect(migratedPolicyConfigSO.attributes.package?.requires_root).toBe(true); + }); + + it('should not backfill `requires_root` field as `true` for other package on Kibana update', () => { + const migratedPolicyConfigSO = migrator.migrate({ + document: getPolicyDoc('other'), + fromVersion: 10, + toVersion: 11, + }); + + expect(migratedPolicyConfigSO.attributes.package!.requires_root).toBe(undefined); + }); + }); +}); diff --git a/x-pack/plugins/fleet/server/saved_objects/migrations/to_v8_15_0.ts b/x-pack/plugins/fleet/server/saved_objects/migrations/to_v8_15_0.ts new file mode 100644 index 0000000000000..bd0771ab7b583 --- /dev/null +++ b/x-pack/plugins/fleet/server/saved_objects/migrations/to_v8_15_0.ts @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { + SavedObjectModelDataBackfillFn, + SavedObjectUnsanitizedDoc, +} from '@kbn/core-saved-objects-server'; + +import type { PackagePolicy } from '../../../common'; + +// backfill existing package policies with packages requiring root in 8.15.0 +const ROOT_PACKAGES = [ + 'endpoint', + 'universal_profiling_agent', + 'system_audit', + 'network_traffic', + 'fim', + 'auditd_manager', +]; + +export const migratePackagePolicySetRequiresRootToV8150: SavedObjectModelDataBackfillFn< + PackagePolicy, + PackagePolicy +> = (packagePolicyDoc) => { + const updatedPackagePolicyDoc: SavedObjectUnsanitizedDoc = packagePolicyDoc; + + if ( + updatedPackagePolicyDoc.attributes.package && + ROOT_PACKAGES.includes(updatedPackagePolicyDoc.attributes.package.name) + ) { + updatedPackagePolicyDoc.attributes.package.requires_root = true; + } + + return { attributes: updatedPackagePolicyDoc.attributes }; +}; diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index a75028be59548..afa7b7c5d92de 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -383,7 +383,10 @@ class AgentPolicyService { throw new FleetError(agentPolicySO.error.message); } - const agentPolicy = { id: agentPolicySO.id, ...agentPolicySO.attributes }; + const agentPolicy = { + id: agentPolicySO.id, + ...agentPolicySO.attributes, + }; if (withPackagePolicies) { agentPolicy.package_policies = diff --git a/x-pack/plugins/fleet/server/services/agents/__snapshots__/uploads.test.ts.snap b/x-pack/plugins/fleet/server/services/agents/__snapshots__/uploads.test.ts.snap new file mode 100644 index 0000000000000..14afaaf1f8f07 --- /dev/null +++ b/x-pack/plugins/fleet/server/services/agents/__snapshots__/uploads.test.ts.snap @@ -0,0 +1,55 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`getAgentUploads should return right list of files 1`] = ` +Array [ + Object { + "actionId": "current-in-progress-action", + "error": undefined, + "filePath": "", + "id": "current-in-progress-action", + "status": "IN_PROGRESS", + }, + Object { + "actionId": "current-complete-action", + "error": undefined, + "filePath": "/api/fleet/agents/files/current-complete-file/current-complete-file.zip", + "id": "current-complete-file", + "status": "READY", + }, + Object { + "actionId": "expired-incomplete-action", + "error": undefined, + "filePath": "", + "id": "expired-incomplete-action", + "status": "EXPIRED", + }, + Object { + "actionId": "expired-complete-action", + "error": undefined, + "filePath": "/api/fleet/agents/files/expired-complete-file/expired-complete-file.zip", + "id": "expired-complete-file", + "status": "READY", + }, + Object { + "actionId": "current-error-action", + "error": "some diagnostics err", + "filePath": "", + "id": "current-error-action", + "status": "FAILED", + }, + Object { + "actionId": "expired-error-action", + "error": "some diagnostics err", + "filePath": "", + "id": "expired-error-action", + "status": "EXPIRED", + }, + Object { + "actionId": "old-complete-action", + "error": undefined, + "filePath": "/api/fleet/agents/files/old-complete-file/old-complete-file.zip", + "id": "old-complete-file", + "status": "READY", + }, +] +`; diff --git a/x-pack/plugins/fleet/server/services/agents/actions.ts b/x-pack/plugins/fleet/server/services/agents/actions.ts index 00a4d6de37d1b..bda3090f25d0e 100644 --- a/x-pack/plugins/fleet/server/services/agents/actions.ts +++ b/x-pack/plugins/fleet/server/services/agents/actions.ts @@ -43,13 +43,14 @@ export async function createAgentAction( newAgentAction: NewAgentAction ): Promise { const actionId = newAgentAction.id ?? uuidv4(); - const timestamp = new Date().toISOString(); + const now = Date.now(); + const timestamp = new Date(now).toISOString(); const body: FleetServerAgentAction = { '@timestamp': timestamp, expiration: newAgentAction.expiration === NO_EXPIRATION ? undefined - : newAgentAction.expiration ?? new Date(Date.now() + ONE_MONTH_IN_MS).toISOString(), + : newAgentAction.expiration ?? new Date(now + ONE_MONTH_IN_MS).toISOString(), agents: newAgentAction.agents, action_id: actionId, data: newAgentAction.data, diff --git a/x-pack/plugins/fleet/server/services/agents/index.ts b/x-pack/plugins/fleet/server/services/agents/index.ts index 2fad96c87bb79..6ffd24f5777cf 100644 --- a/x-pack/plugins/fleet/server/services/agents/index.ts +++ b/x-pack/plugins/fleet/server/services/agents/index.ts @@ -15,7 +15,7 @@ export * from './reassign'; export * from './update_agent_tags'; export * from './action_status'; export * from './request_diagnostics'; -export { getAgentUploads, getAgentUploadFile } from './uploads'; +export { getAgentUploads, getAgentUploadFile, deleteAgentUploadFile } from './uploads'; export { AgentServiceImpl } from './agent_service'; export type { AgentClient, AgentService } from './agent_service'; export { BulkActionsResolver } from './bulk_actions_resolver'; diff --git a/x-pack/plugins/fleet/server/services/agents/request_diagnostics.test.ts b/x-pack/plugins/fleet/server/services/agents/request_diagnostics.test.ts index b297e4cb7c584..a6aa09ee2a36d 100644 --- a/x-pack/plugins/fleet/server/services/agents/request_diagnostics.test.ts +++ b/x-pack/plugins/fleet/server/services/agents/request_diagnostics.test.ts @@ -31,6 +31,7 @@ describe('requestDiagnostics', () => { body: expect.objectContaining({ agents: ['agent-in-regular-policy'], type: 'REQUEST_DIAGNOSTICS', + expiration: expect.anything(), }), index: '.fleet-actions', }) @@ -50,6 +51,7 @@ describe('requestDiagnostics', () => { body: expect.objectContaining({ agents: ['agent-in-regular-policy-newer', 'agent-in-regular-policy-newer2'], type: 'REQUEST_DIAGNOSTICS', + expiration: expect.anything(), }), index: '.fleet-actions', }) @@ -66,6 +68,7 @@ describe('requestDiagnostics', () => { body: expect.objectContaining({ agents: ['agent-in-regular-policy-newer', 'agent-in-regular-policy'], type: 'REQUEST_DIAGNOSTICS', + expiration: expect.anything(), }), index: '.fleet-actions', }) diff --git a/x-pack/plugins/fleet/server/services/agents/request_diagnostics.ts b/x-pack/plugins/fleet/server/services/agents/request_diagnostics.ts index e2ed7e7ae8f1f..323af2ad29314 100644 --- a/x-pack/plugins/fleet/server/services/agents/request_diagnostics.ts +++ b/x-pack/plugins/fleet/server/services/agents/request_diagnostics.ts @@ -9,7 +9,7 @@ import type { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/ import type { RequestDiagnosticsAdditionalMetrics } from '../../../common/types'; -import { SO_SEARCH_LIMIT } from '../../constants'; +import { SO_SEARCH_LIMIT, REQUEST_DIAGNOSTICS_TIMEOUT_MS } from '../../constants'; import type { GetAgentsOptions } from '.'; import { getAgents, getAgentsByKuery } from './crud'; @@ -20,8 +20,6 @@ import { requestDiagnosticsBatch, } from './request_diagnostics_action_runner'; -const REQUEST_DIAGNOSTICS_TIMEOUT_MS = 3 * 60 * 1000; // 3 hours; - export async function requestDiagnostics( esClient: ElasticsearchClient, agentId: string, diff --git a/x-pack/plugins/fleet/server/services/agents/request_diagnostics_action_runner.ts b/x-pack/plugins/fleet/server/services/agents/request_diagnostics_action_runner.ts index a2d2d753eaa71..073297fabe8fa 100644 --- a/x-pack/plugins/fleet/server/services/agents/request_diagnostics_action_runner.ts +++ b/x-pack/plugins/fleet/server/services/agents/request_diagnostics_action_runner.ts @@ -9,11 +9,9 @@ import { v4 as uuidv4 } from 'uuid'; import type { ElasticsearchClient } from '@kbn/core/server'; import type { RequestDiagnosticsAdditionalMetrics } from '../../../common/types'; - import { isAgentRequestDiagnosticsSupported } from '../../../common/services'; - import type { Agent } from '../../types'; - +import { REQUEST_DIAGNOSTICS_TIMEOUT_MS } from '../../constants'; import { FleetError } from '../../errors'; import { ActionRunner } from './action_runner'; @@ -64,6 +62,7 @@ export async function requestDiagnosticsBatch( agents: agentIds, created_at: now, type: 'REQUEST_DIAGNOSTICS', + expiration: new Date(Date.now() + REQUEST_DIAGNOSTICS_TIMEOUT_MS).toISOString(), total, data: { additional_metrics: options.additionalMetrics, diff --git a/x-pack/plugins/fleet/server/services/agents/uploads.test.ts b/x-pack/plugins/fleet/server/services/agents/uploads.test.ts new file mode 100644 index 0000000000000..213b0cc217953 --- /dev/null +++ b/x-pack/plugins/fleet/server/services/agents/uploads.test.ts @@ -0,0 +1,134 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; + +import { AGENT_ACTIONS_INDEX, AGENT_ACTIONS_RESULTS_INDEX } from '../../../common'; +import { FILE_STORAGE_METADATA_AGENT_INDEX } from '../../constants'; + +import { appContextService } from '../app_context'; +import { createAppContextStartContractMock } from '../../mocks'; + +import { deleteAgentUploadFile, getAgentUploads } from './uploads'; +import { + AGENT_ACTIONS_FIXTURES, + AGENT_ACTIONS_RESULTS_FIXTURES, + FILES_METADATA_BY_ACTION_ID, +} from './uploads.test_fixtures'; + +describe('getAgentUploads', () => { + const esClient = {} as ElasticsearchClient; + + beforeAll(async () => { + appContextService.start(createAppContextStartContractMock()); + }); + + afterAll(() => { + appContextService.stop(); + }); + + it('should return right list of files', async () => { + esClient.search = jest.fn().mockImplementation(({ index, query }) => { + if (index === AGENT_ACTIONS_INDEX) { + return { hits: { hits: AGENT_ACTIONS_FIXTURES } }; + } + + if (index === AGENT_ACTIONS_RESULTS_INDEX) { + return { hits: { hits: AGENT_ACTIONS_RESULTS_FIXTURES } }; + } + + if (index === FILE_STORAGE_METADATA_AGENT_INDEX) { + const actionId = query.bool.filter.bool.must[1].term.action_id as string; + if (FILES_METADATA_BY_ACTION_ID[actionId]) { + return { hits: { hits: [FILES_METADATA_BY_ACTION_ID[actionId]] } }; + } else { + return { hits: { hits: [] } }; + } + } + }); + + const response = await getAgentUploads(esClient, 'agent-1'); + expect(response.length).toBe(7); + expect(response.filter((i) => i.status === 'DELETED').length).toBe(0); + response.forEach((item) => { + expect(item.name).toBeDefined(); + if (item.status === 'READY') { + expect(item.name).toEqual(`${item.id}.zip`); + } else { + expect(item.name).toMatch(new RegExp(`^elastic-agent-diagnostics-.*\.zip$`)); + } + }); + expect(response.map(({ createTime, name, ...rest }) => rest)).toMatchSnapshot(); + }); +}); + +describe('deleteAgentUploadFile', () => { + const esClient = {} as ElasticsearchClient; + const id = 'agent-upload-file-id'; + + beforeAll(async () => { + appContextService.start(createAppContextStartContractMock()); + }); + + afterAll(() => { + appContextService.stop(); + }); + + describe('should return success', () => { + it('if the file was deleted and metadata was updated normally', async () => { + esClient.deleteByQuery = jest.fn().mockResolvedValueOnce({ deleted: 1 }); + esClient.updateByQuery = jest.fn().mockResolvedValueOnce({ total: 1 }); + const response = await deleteAgentUploadFile(esClient, id); + expect(esClient.deleteByQuery).toHaveBeenCalledTimes(1); + expect(esClient.updateByQuery).toHaveBeenCalledTimes(1); + expect(response).toEqual({ id, deleted: true }); + }); + it('if no files needed to be deleted and metadata was updated normally', async () => { + esClient.deleteByQuery = jest.fn().mockResolvedValueOnce({ total: 0 }); + esClient.updateByQuery = jest.fn().mockResolvedValueOnce({ total: 1 }); + const response = await deleteAgentUploadFile(esClient, id); + expect(esClient.deleteByQuery).toHaveBeenCalledTimes(1); + expect(esClient.updateByQuery).toHaveBeenCalledTimes(1); + expect(response).toEqual({ id, deleted: true }); + }); + }); + + describe('should throw an error', () => { + it('if data file deletion failed due to ES client error', async () => { + esClient.deleteByQuery = jest.fn().mockRejectedValueOnce(new Error('some es error')); + esClient.updateByQuery = jest.fn(); + await expect(deleteAgentUploadFile(esClient, id)).rejects.toThrow('some es error'); + expect(esClient.deleteByQuery).toHaveBeenCalledTimes(1); + expect(esClient.updateByQuery).not.toHaveBeenCalled(); + }); + it('if data file deletion failed due to no files deleted', async () => { + esClient.deleteByQuery = jest.fn().mockResolvedValueOnce({ deleted: 0, total: 1 }); + esClient.updateByQuery = jest.fn(); + await expect(deleteAgentUploadFile(esClient, id)).rejects.toThrow( + `Failed to delete file ${id} from file storage data stream` + ); + expect(esClient.deleteByQuery).toHaveBeenCalledTimes(1); + expect(esClient.updateByQuery).not.toHaveBeenCalled(); + }); + it('if metadata deletion failed due to ES client error', async () => { + esClient.deleteByQuery = jest.fn().mockResolvedValueOnce({ total: 0 }); + esClient.updateByQuery = jest.fn().mockRejectedValueOnce(new Error('some es error')); + await expect(deleteAgentUploadFile(esClient, id)).rejects.toThrow('some es error'); + expect(esClient.deleteByQuery).toHaveBeenCalledTimes(1); + expect(esClient.updateByQuery).toHaveBeenCalledTimes(1); + }); + it('if metadata deletion failed due to no files deleted', async () => { + esClient.deleteByQuery = jest.fn().mockResolvedValueOnce({ total: 0 }); + esClient.updateByQuery = jest.fn().mockResolvedValueOnce({ total: 0 }); + await expect(deleteAgentUploadFile(esClient, id)).rejects.toThrow( + `Failed to update file ${id} metadata` + ); + expect(esClient.deleteByQuery).toHaveBeenCalledTimes(1); + expect(esClient.updateByQuery).toHaveBeenCalledTimes(1); + }); + }); +}); diff --git a/x-pack/plugins/fleet/server/services/agents/uploads.test_fixtures.ts b/x-pack/plugins/fleet/server/services/agents/uploads.test_fixtures.ts new file mode 100644 index 0000000000000..c749601d2af62 --- /dev/null +++ b/x-pack/plugins/fleet/server/services/agents/uploads.test_fixtures.ts @@ -0,0 +1,173 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import Moment from 'moment'; + +export const AGENT_ACTIONS_FIXTURES = [ + { + _source: { + action_id: 'current-in-progress-action', + '@timestamp': Moment().subtract('5', 'minute').toISOString(), + expiration: Moment().add(1, 'day').toISOString(), + }, + }, + { + _source: { + action_id: 'current-complete-action', + '@timestamp': Moment().subtract('5', 'minute').toISOString(), + expiration: Moment().add(1, 'day').toISOString(), + }, + }, + { + _source: { + action_id: 'expired-incomplete-action', + '@timestamp': Moment().subtract(6, 'hour').toISOString(), + expiration: Moment().subtract(3, 'hour').toISOString(), + }, + }, + { + _source: { + action_id: 'expired-complete-action', + '@timestamp': Moment().subtract(6, 'hour').toISOString(), + expiration: Moment().subtract(3, 'hour').toISOString(), + }, + }, + { + _source: { + action_id: 'current-error-action', + '@timestamp': Moment().subtract('5', 'minute').toISOString(), + expiration: Moment().add(1, 'day').toISOString(), + }, + }, + { + _source: { + action_id: 'expired-error-action', + '@timestamp': Moment().subtract(6, 'hour').toISOString(), + expiration: Moment().subtract(3, 'hour').toISOString(), + }, + }, + { + _source: { + action_id: 'current-deleted-action', + '@timestamp': Moment().subtract('5', 'minute').toISOString(), + expiration: Moment().add(1, 'day').toISOString(), + }, + }, + { + _source: { + action_id: 'expired-deleted-action', + '@timestamp': Moment().subtract(6, 'hour').toISOString(), + expiration: Moment().subtract(3, 'hour').toISOString(), + }, + }, + { + _source: { + action_id: 'old-incomplete-action', + '@timestamp': Moment().subtract(90, 'day').toISOString(), + expiration: Moment().subtract(89, 'day').toISOString(), + }, + }, + { + _source: { + action_id: 'old-complete-action', + '@timestamp': Moment().subtract(90, 'day').toISOString(), + expiration: Moment().subtract(89, 'day').toISOString(), + }, + }, +]; + +export const AGENT_ACTIONS_RESULTS_FIXTURES = [ + { + _source: { + action_id: 'current-in-progress-action', + }, + }, + { + _source: { + action_id: 'current-complete-action', + data: { upload_id: 'current-complete-file' }, + }, + }, + { + _source: { + action_id: 'expired-incomplete-action', + }, + }, + { + _source: { + action_id: 'expired-complete-action', + data: { upload_id: 'expired-complete-file' }, + }, + }, + { + _source: { + action_id: 'current-error-action', + error: 'some diagnostics err', + }, + }, + { + _source: { + action_id: 'expired-error-action', + error: 'some diagnostics err', + }, + }, + { + _source: { + action_id: 'current-deleted-action', + data: { upload_id: 'current-deleted-file' }, + }, + }, + { + _source: { + action_id: 'expired-deleted-action', + data: { upload_id: 'expired-deleted-file' }, + }, + }, + { + _source: { + action_id: 'old-incomplete-action', + }, + }, + { + _source: { + action_id: 'old-complete-action', + data: { upload_id: 'old-complete-file' }, + }, + }, +]; + +export const FILES_METADATA_BY_ACTION_ID: Record = { + 'current-complete-action': { + _id: 'current-complete-file', + _source: { + file: { name: 'current-complete-file.zip', Status: 'READY' }, + }, + }, + 'expired-complete-action': { + _id: 'expired-complete-file', + _source: { + file: { name: 'expired-complete-file.zip', Status: 'READY' }, + }, + }, + 'current-deleted-action': { + _id: 'current-complete-file', + _source: { + file: { name: 'current-complete-file.zip', Status: 'DELETED' }, + }, + }, + 'expired-deleted-action': { + _id: 'expired-complete-file', + _source: { + file: { name: 'expired-complete-file.zip', Status: 'DELETED' }, + }, + }, + 'old-complete-action': { + _id: 'old-complete-file', + _source: { + file: { name: 'old-complete-file.zip', Status: 'READY' }, + }, + }, +}; diff --git a/x-pack/plugins/fleet/server/services/agents/uploads.ts b/x-pack/plugins/fleet/server/services/agents/uploads.ts index bc2c52e433473..27d0a52eeb3c7 100644 --- a/x-pack/plugins/fleet/server/services/agents/uploads.ts +++ b/x-pack/plugins/fleet/server/services/agents/uploads.ts @@ -20,12 +20,14 @@ import { AGENT_ACTIONS_RESULTS_INDEX, agentRouteService, } from '../../../common'; - +import type { DeleteAgentUploadResponse } from '../../../common/types'; import { FILE_STORAGE_DATA_AGENT_INDEX, FILE_STORAGE_METADATA_AGENT_INDEX, SO_SEARCH_LIMIT, } from '../../constants'; +import { updateFilesStatus } from '../files'; +import { FleetError } from '../../errors'; export async function getAgentUploads( esClient: ElasticsearchClient, @@ -48,7 +50,7 @@ export async function getAgentUploads( if (fileResponse.hits.hits.length === 0) { appContextService .getLogger() - .debug(`No matches for action_id ${actionId} and agent_id ${agentId}`); + .trace(`No matches for action_id ${actionId} and agent_id ${agentId}`); return; } return { @@ -70,6 +72,19 @@ export async function getAgentUploads( const results: AgentDiagnostics[] = []; for (const action of actions) { const file = await getFile(action.actionId); + + // File list is initially built from list of diagnostic actions. + // If file was deleted intentially by ILM policy or user based on the meta information, + // or if the meta information does not exist AND the action is old (new actions are + // ok to show because we want to show in progress files) + // skip returning this action/file information. + if ( + file?.Status === 'DELETED' || + (!file && Date.parse(action.timestamp!) < Date.now() - 89 * 24 * 3600 * 1000) + ) { + continue; + } + const fileName = file?.name ?? `elastic-agent-diagnostics-${moment @@ -78,7 +93,7 @@ export async function getAgentUploads( const filePath = file ? agentRouteService.getAgentFileDownloadLink(file.id, file.name) : ''; const isActionExpired = action.expiration ? Date.parse(action.expiration) < Date.now() : false; const status = - file?.Status ?? (action.error ? 'FAILED' : isActionExpired ? 'EXPIRED' : 'IN_PROGRESS'); + file?.Status ?? (isActionExpired ? 'EXPIRED' : action.error ? 'FAILED' : 'IN_PROGRESS'); const result = { actionId: action.actionId, id: file?.id ?? action.actionId, @@ -216,6 +231,61 @@ export async function getAgentUploadFile( } } +export async function deleteAgentUploadFile( + esClient: ElasticsearchClient, + id: string +): Promise { + try { + // We manually delete the documents from the data streams with `_delete_by_query` + // because data streams do not support single deletes. See: + // https://www.elastic.co/guide/en/elasticsearch/reference/current/data-streams.html#data-streams-append-only + + // Delete the file from the file storage data stream + const filesDeleteResponse = await esClient.deleteByQuery({ + index: FILE_STORAGE_DATA_AGENT_INDEX, + refresh: true, + body: { + query: { + match: { + bid: id, // Use `bid` instead of `_id` because `_id` has additional suffixes + }, + }, + }, + }); + + if ( + !!( + (filesDeleteResponse.deleted && filesDeleteResponse.deleted > 0) || + filesDeleteResponse.total === 0 + ) + ) { + // Update the metadata to mark the file as deleted + const updateMetadataStatusResponse = ( + await updateFilesStatus( + esClient, + undefined, + { [FILE_STORAGE_METADATA_AGENT_INDEX]: new Set([id]) }, + 'DELETED' + ) + )[0]; + + if (updateMetadataStatusResponse.total === 0) { + throw new FleetError(`Failed to update file ${id} metadata`); + } + + return { + id, + deleted: true, + }; + } else { + throw new FleetError(`Failed to delete file ${id} from file storage data stream`); + } + } catch (error) { + appContextService.getLogger().error(error); + throw error; + } +} + export function getDownloadHeadersForFile(fileName: string): ResponseHeaders { return { 'content-type': 'application/octet-stream', diff --git a/x-pack/plugins/fleet/server/services/files/index.ts b/x-pack/plugins/fleet/server/services/files/index.ts index 48303c3611fc7..203bc374b2bf1 100644 --- a/x-pack/plugins/fleet/server/services/files/index.ts +++ b/x-pack/plugins/fleet/server/services/files/index.ts @@ -147,7 +147,7 @@ export async function fileIdsWithoutChunksByIndex( */ export function updateFilesStatus( esClient: ElasticsearchClient, - abortController: AbortController, + abortController: AbortController | undefined, fileIdsByIndex: FileIdsByIndex, status: FileStatus ): Promise { @@ -168,7 +168,7 @@ export function updateFilesStatus( lang: 'painless', }, }, - { signal: abortController.signal } + abortController ? { signal: abortController.signal } : {} ) .catch((err) => { Error.captureStackTrace(err); diff --git a/x-pack/plugins/fleet/server/services/package_policy.ts b/x-pack/plugins/fleet/server/services/package_policy.ts index 45753540af256..05ccacad3d704 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.ts @@ -328,6 +328,13 @@ class PackagePolicyClientImpl implements PackagePolicyClient { logger, }); } + + if (enrichedPackagePolicy.package && pkgInfo?.agent?.privileges?.root) { + enrichedPackagePolicy.package = { + ...enrichedPackagePolicy.package, + requires_root: pkgInfo?.agent?.privileges?.root ?? false, + }; + } } const isoDate = new Date().toISOString(); @@ -457,6 +464,13 @@ class PackagePolicyClientImpl implements PackagePolicyClient { : inputs; elasticsearch = pkgInfo?.elasticsearch; + + if (packagePolicy.package && pkgInfo?.agent?.privileges?.root) { + packagePolicy.package = { + ...packagePolicy.package, + requires_root: pkgInfo?.agent?.privileges?.root ?? false, + }; + } } policiesToCreate.push({ @@ -862,6 +876,13 @@ class PackagePolicyClientImpl implements PackagePolicyClient { assetsMap ); elasticsearchPrivileges = pkgInfo.elasticsearch?.privileges; + + if (restOfPackagePolicy.package && pkgInfo?.agent?.privileges?.root) { + restOfPackagePolicy.package = { + ...restOfPackagePolicy.package, + requires_root: pkgInfo?.agent?.privileges?.root ?? false, + }; + } } // Handle component template/mappings updates for experimental features, e.g. synthetic source @@ -1042,6 +1063,13 @@ class PackagePolicyClientImpl implements PackagePolicyClient { assetsMap ); elasticsearchPrivileges = pkgInfo.elasticsearch?.privileges; + + if (restOfPackagePolicy.package && pkgInfo?.agent?.privileges?.root) { + restOfPackagePolicy.package = { + ...restOfPackagePolicy.package, + requires_root: pkgInfo?.agent?.privileges?.root ?? false, + }; + } } } diff --git a/x-pack/plugins/fleet/server/services/telemetry/fleet_usage_sender.ts b/x-pack/plugins/fleet/server/services/telemetry/fleet_usage_sender.ts index 367d7f0ce0ff9..ca23ef3bb8fe0 100644 --- a/x-pack/plugins/fleet/server/services/telemetry/fleet_usage_sender.ts +++ b/x-pack/plugins/fleet/server/services/telemetry/fleet_usage_sender.ts @@ -24,7 +24,7 @@ const FLEET_AGENTS_EVENT_TYPE = 'fleet_agents'; export class FleetUsageSender { private taskManager?: TaskManagerStartContract; - private taskVersion = '1.1.5'; + private taskVersion = '1.1.6'; private taskType = 'Fleet-Usage-Sender'; private wasStarted: boolean = false; private interval = '1h'; diff --git a/x-pack/plugins/fleet/server/services/telemetry/fleet_usages_schema.ts b/x-pack/plugins/fleet/server/services/telemetry/fleet_usages_schema.ts index 574c5dac1ad6a..912d0c0413c06 100644 --- a/x-pack/plugins/fleet/server/services/telemetry/fleet_usages_schema.ts +++ b/x-pack/plugins/fleet/server/services/telemetry/fleet_usages_schema.ts @@ -282,6 +282,18 @@ export const fleetUsagesSchema: RootSchema = { description: 'The total number of enrolled Fleet Server agents currently offline', }, }, + inactive: { + type: 'long', + _meta: { + description: 'The total number of enrolled Fleet Server agents currently inactive', + }, + }, + unenrolled: { + type: 'long', + _meta: { + description: 'The total number of unenrolled Fleet Server agents', + }, + }, num_host_urls: { type: 'long', _meta: { diff --git a/x-pack/plugins/fleet/server/types/models/package_policy.ts b/x-pack/plugins/fleet/server/types/models/package_policy.ts index b712986556068..fdde855717842 100644 --- a/x-pack/plugins/fleet/server/types/models/package_policy.ts +++ b/x-pack/plugins/fleet/server/types/models/package_policy.ts @@ -105,6 +105,7 @@ const PackagePolicyBaseSchema = { title: schema.string(), version: schema.string(), experimental_data_stream_features: schema.maybe(ExperimentalDataStreamFeatures), + requires_root: schema.maybe(schema.boolean()), }) ), // Deprecated TODO create remove issue @@ -148,6 +149,7 @@ const CreatePackagePolicyProps = { title: schema.maybe(schema.string()), version: schema.string(), experimental_data_stream_features: schema.maybe(ExperimentalDataStreamFeatures), + requires_root: schema.maybe(schema.boolean()), }) ), // Deprecated TODO create remove issue @@ -222,6 +224,7 @@ export const SimplifiedCreatePackagePolicyRequestBodySchema = name: schema.string(), version: schema.string(), experimental_data_stream_features: schema.maybe(ExperimentalDataStreamFeatures), + requires_root: schema.maybe(schema.boolean()), }), }); diff --git a/x-pack/plugins/fleet/server/types/rest_spec/agent.ts b/x-pack/plugins/fleet/server/types/rest_spec/agent.ts index 0ab7ece50f87f..4bbd065e23003 100644 --- a/x-pack/plugins/fleet/server/types/rest_spec/agent.ts +++ b/x-pack/plugins/fleet/server/types/rest_spec/agent.ts @@ -197,6 +197,12 @@ export const GetAgentUploadFileRequestSchema = { }), }; +export const DeleteAgentUploadFileRequestSchema = { + params: schema.object({ + fileId: schema.string(), + }), +}; + export const PostBulkAgentReassignRequestSchema = { body: schema.object({ policy_id: schema.string(), diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/__snapshots__/extend_index_management.test.tsx.snap b/x-pack/plugins/index_lifecycle_management/__jest__/__snapshots__/extend_index_management.test.tsx.snap index 230e6ad33df54..31555edfad65f 100644 --- a/x-pack/plugins/index_lifecycle_management/__jest__/__snapshots__/extend_index_management.test.tsx.snap +++ b/x-pack/plugins/index_lifecycle_management/__jest__/__snapshots__/extend_index_management.test.tsx.snap @@ -171,7 +171,7 @@ exports[`extend index management ilm summary extension should render a phase def > , + + + , domNode ); handlers.onDestroy(() => ReactDOM.unmountComponentAtNode(domNode)); diff --git a/x-pack/plugins/maps/public/trigger_actions/filter_by_map_extent/action.ts b/x-pack/plugins/maps/public/trigger_actions/filter_by_map_extent/action.ts index a368dc65b26fe..f0a55a20229cb 100644 --- a/x-pack/plugins/maps/public/trigger_actions/filter_by_map_extent/action.ts +++ b/x-pack/plugins/maps/public/trigger_actions/filter_by_map_extent/action.ts @@ -6,7 +6,12 @@ */ import { i18n } from '@kbn/i18n'; -import { type EmbeddableApiContext, apiHasType, apiIsOfType } from '@kbn/presentation-publishing'; +import { + type EmbeddableApiContext, + apiHasType, + apiIsOfType, + areTriggersDisabled, +} from '@kbn/presentation-publishing'; import { createAction } from '@kbn/ui-actions-plugin/public'; import { apiHasVisualizeConfig } from '@kbn/visualizations-plugin/public'; import { type FilterByMapExtentActionApi } from './types'; @@ -53,7 +58,7 @@ export const filterByMapExtentAction = createAction({ return 'filter'; }, isCompatible: async ({ embeddable }: EmbeddableApiContext) => { - if (!isApiCompatible(embeddable) || embeddable.disableTriggers) return false; + if (!isApiCompatible(embeddable) || areTriggersDisabled(embeddable)) return false; return ( apiIsOfType(embeddable, MAP_SAVED_OBJECT_TYPE) || (apiHasVisualizeConfig(embeddable) && isLegacyMapApi(embeddable)) diff --git a/x-pack/plugins/ml/public/application/components/anomalies_table/anomaly_details_utils.tsx b/x-pack/plugins/ml/public/application/components/anomalies_table/anomaly_details_utils.tsx index e3d1693eb3c4a..87620dde12f40 100644 --- a/x-pack/plugins/ml/public/application/components/anomalies_table/anomaly_details_utils.tsx +++ b/x-pack/plugins/ml/public/application/components/anomalies_table/anomaly_details_utils.tsx @@ -10,14 +10,13 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { - EuiToolTip, - EuiIcon, EuiFlexGroup, EuiFlexItem, useEuiTheme, EuiText, EuiSpacer, EuiLink, + EuiIconTip, } from '@elastic/eui'; import { getAnomalyScoreExplanationImpactValue, @@ -231,43 +230,49 @@ export const DetailsItems: FC<{ items.push({ title: ( - + {i18n.translate('xpack.ml.anomaliesTable.anomalyDetails.recordScoreTitle', { + defaultMessage: 'Record score', })} - > - - {i18n.translate('xpack.ml.anomaliesTable.anomalyDetails.recordScoreTitle', { - defaultMessage: 'Record score', +   + - - + /> + ), description: Math.floor(1000 * source.record_score) / 1000, }); items.push({ title: ( - - - {i18n.translate('xpack.ml.anomaliesTable.anomalyDetails.initialRecordScoreTitle', { - defaultMessage: 'Initial record score', - })} - - - + + {i18n.translate('xpack.ml.anomaliesTable.anomalyDetails.initialRecordScoreTitle', { + defaultMessage: 'Initial record score', + })} +   + + ), description: Math.floor(1000 * source.initial_record_score) / 1000, }); @@ -368,24 +373,27 @@ export const AnomalyExplanationDetails: FC<{ anomaly: MlAnomaliesTableRecord }> if (scoreDifference > ACCEPTABLE_NORMALIZATION) { explanationDetails.push({ title: ( - - - - - - + + +   + + ), description: ( @@ -406,21 +414,24 @@ export const AnomalyExplanationDetails: FC<{ anomaly: MlAnomaliesTableRecord }> if (explanation.anomaly_characteristics_impact !== undefined) { impactDetails.push({ title: ( - - - - - - + + +   + + ), description: , }); @@ -429,18 +440,21 @@ export const AnomalyExplanationDetails: FC<{ anomaly: MlAnomaliesTableRecord }> if (explanation.single_bucket_impact !== undefined) { impactDetails.push({ title: ( - - - - - - + + +   + + ), description: , }); @@ -448,18 +462,21 @@ export const AnomalyExplanationDetails: FC<{ anomaly: MlAnomaliesTableRecord }> if (explanation.multi_bucket_impact !== undefined) { impactDetails.push({ title: ( - - - - - - + + +   + + ), description: , }); @@ -467,24 +484,27 @@ export const AnomalyExplanationDetails: FC<{ anomaly: MlAnomaliesTableRecord }> if (explanation.high_variance_penalty !== undefined) { impactDetails.push({ title: ( - - - - - - + + +   + + ), description: explanation.high_variance_penalty ? yes : no, }); @@ -492,24 +512,27 @@ export const AnomalyExplanationDetails: FC<{ anomaly: MlAnomaliesTableRecord }> if (explanation.multimodal_distribution !== undefined) { impactDetails.push({ title: ( - - - - - - + + +   + + ), description: explanation.multimodal_distribution ? yes : no, }); @@ -517,24 +540,27 @@ export const AnomalyExplanationDetails: FC<{ anomaly: MlAnomaliesTableRecord }> if (explanation.incomplete_bucket_penalty !== undefined) { impactDetails.push({ title: ( - - - - - - + + +   + + ), description: explanation.incomplete_bucket_penalty ? yes : no, }); diff --git a/x-pack/plugins/ml/public/application/components/help_popover/help_popover.tsx b/x-pack/plugins/ml/public/application/components/help_popover/help_popover.tsx index aa7bf496b1051..eccfe901d3c3b 100644 --- a/x-pack/plugins/ml/public/application/components/help_popover/help_popover.tsx +++ b/x-pack/plugins/ml/public/application/components/help_popover/help_popover.tsx @@ -51,7 +51,7 @@ export const HelpPopover: FC> = ({ > {title && {title}} - + {children}
diff --git a/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/jobs_list_page.tsx b/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/jobs_list_page.tsx index 7f5929354b61f..0df22e8cad7fb 100644 --- a/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/jobs_list_page.tsx +++ b/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/jobs_list_page.tsx @@ -113,11 +113,19 @@ export const JobsListPage: FC = ({ } if (accessDenied) { - return ; + return ( + + + + ); } if (isPlatinumOrTrialLicense === false) { - return ; + return ( + + + + ); } return ( diff --git a/x-pack/plugins/ml/public/cases/anomaly_swim_lane_attachment.tsx b/x-pack/plugins/ml/public/cases/anomaly_swim_lane_attachment.tsx index 5a0429725eb79..08406d4acc44f 100644 --- a/x-pack/plugins/ml/public/cases/anomaly_swim_lane_attachment.tsx +++ b/x-pack/plugins/ml/public/cases/anomaly_swim_lane_attachment.tsx @@ -86,16 +86,16 @@ export const initComponent = memoize((fieldFormats: FieldFormatsStart) => { maybeId={inputProps.id} type={CASE_ATTACHMENT_TYPE_ID_ANOMALY_SWIMLANE} - state={{ - rawState: inputProps, - }} - parentApi={{ + getParentApi={() => ({ + getSerializedStateForChild: () => ({ + rawState: inputProps, + }), executionContext: { type: 'cases', description: caseData.title, id: caseData.id, }, - }} + })} /> ); diff --git a/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.test.tsx b/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.test.tsx index 65e09e1ef0669..4765950b341f9 100644 --- a/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.test.tsx +++ b/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.test.tsx @@ -100,16 +100,14 @@ describe('getAnomalySwimLaneEmbeddableFactory', () => { maybeId={'maybe_id'} type={ANOMALY_SWIMLANE_EMBEDDABLE_TYPE} - state={{ - rawState, - }} onApiAvailable={onApiAvailable} - parentApi={{ + getParentApi={() => ({ + getSerializedStateForChild: () => ({ rawState }), executionContext: { type: 'dashboard', id: 'dashboard-id', }, - }} + })} /> ); diff --git a/x-pack/plugins/ml/public/shared_components/anomaly_swim_lane.tsx b/x-pack/plugins/ml/public/shared_components/anomaly_swim_lane.tsx index 18594d02c3cb3..b7748a753cc5c 100644 --- a/x-pack/plugins/ml/public/shared_components/anomaly_swim_lane.tsx +++ b/x-pack/plugins/ml/public/shared_components/anomaly_swim_lane.tsx @@ -9,6 +9,7 @@ import type { KibanaExecutionContext } from '@kbn/core/public'; import { ReactEmbeddableRenderer } from '@kbn/embeddable-plugin/public'; import type { AggregateQuery, Filter, Query, TimeRange } from '@kbn/es-query'; import type { PublishesWritableUnifiedSearch } from '@kbn/presentation-publishing'; +import type { HasSerializedChildState } from '@kbn/presentation-containers'; import React, { useEffect, useMemo, useRef, type FC } from 'react'; import { BehaviorSubject } from 'rxjs'; import type { @@ -72,13 +73,16 @@ export const AnomalySwimLane: FC = ({ ); const parentApi = useMemo< - PublishesWritableUnifiedSearch & { executionContext: KibanaExecutionContext } + PublishesWritableUnifiedSearch & { + executionContext: KibanaExecutionContext; + } & HasSerializedChildState >(() => { const filters$ = new BehaviorSubject(filters); const query$ = new BehaviorSubject(query); const timeRange$ = new BehaviorSubject(timeRange); return { + getSerializedStateForChild: () => ({ rawState }), filters$, setFilters: (newFilters) => { filters$.next(newFilters); @@ -115,10 +119,7 @@ export const AnomalySwimLane: FC = ({ maybeId={id} type={ANOMALY_SWIMLANE_EMBEDDABLE_TYPE} - state={{ - rawState, - }} - parentApi={parentApi} + getParentApi={() => parentApi} onApiAvailable={(api) => { embeddableApi.current = api; }} diff --git a/x-pack/plugins/observability_solution/apm/common/service_groups.ts b/x-pack/plugins/observability_solution/apm/common/service_groups.ts index b93ecffc2ab5b..035aa06c83d32 100644 --- a/x-pack/plugins/observability_solution/apm/common/service_groups.ts +++ b/x-pack/plugins/observability_solution/apm/common/service_groups.ts @@ -5,9 +5,8 @@ * 2.0. */ -import { fromKueryExpression } from '@kbn/es-query'; +import { getKqlFieldNamesFromExpression } from '@kbn/es-query'; import { i18n } from '@kbn/i18n'; -import { getKueryFields } from './utils/get_kuery_fields'; import { AGENT_NAME, SERVICE_NAME, @@ -51,7 +50,7 @@ export function validateServiceGroupKuery(kuery: string): { message?: string; } { try { - const kueryFields = getKueryFields([fromKueryExpression(kuery)]); + const kueryFields = getKqlFieldNamesFromExpression(kuery); const unsupportedKueryFields = kueryFields.filter((fieldName) => !isSupportedField(fieldName)); if (unsupportedKueryFields.length === 0) { return { isValidFields: true, isValidSyntax: true }; diff --git a/x-pack/plugins/observability_solution/apm/common/utils/get_kuery_fields.test.ts b/x-pack/plugins/observability_solution/apm/common/utils/get_kuery_fields.test.ts deleted file mode 100644 index e8620c9580adf..0000000000000 --- a/x-pack/plugins/observability_solution/apm/common/utils/get_kuery_fields.test.ts +++ /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 { getKueryFields } from './get_kuery_fields'; -import { fromKueryExpression } from '@kbn/es-query'; - -describe('get kuery fields', () => { - it('returns single kuery field', () => { - const kuery = 'service.name: my-service'; - const kueryNode = fromKueryExpression(kuery); - expect(getKueryFields([kueryNode])).toEqual(['service.name']); - }); - - it('returns kuery fields with wildcard', () => { - const kuery = 'service.name: *'; - const kueryNode = fromKueryExpression(kuery); - expect(getKueryFields([kueryNode])).toEqual(['service.name']); - }); - - it('returns multiple fields used AND operator', () => { - const kuery = 'service.name: my-service AND service.environment: production'; - const kueryNode = fromKueryExpression(kuery); - expect(getKueryFields([kueryNode])).toEqual(['service.name', 'service.environment']); - }); - - it('returns multiple kuery fields with OR operator', () => { - const kuery = 'network.carrier.mcc: test or child.id: 33'; - const kueryNode = fromKueryExpression(kuery); - expect(getKueryFields([kueryNode])).toEqual(['network.carrier.mcc', 'child.id']); - }); - - it('returns multiple kuery fields with wildcard', () => { - const kuery = 'network.carrier.mcc:* or child.id: *'; - const kueryNode = fromKueryExpression(kuery); - expect(getKueryFields([kueryNode])).toEqual(['network.carrier.mcc', 'child.id']); - }); - - it('returns single kuery fields with gt operator', () => { - const kuery = 'transaction.duration.aggregate > 10'; - const kueryNode = fromKueryExpression(kuery); - expect(getKueryFields([kueryNode])).toEqual(['transaction.duration.aggregate']); - }); - - it('returns dublicate fields', () => { - const kueries = ['service.name: my-service', 'service.name: my-service and trace.id: trace']; - - const kueryNodes = kueries.map((kuery) => fromKueryExpression(kuery)); - expect(getKueryFields(kueryNodes)).toEqual(['service.name', 'service.name', 'trace.id']); - }); - - it('returns multiple fields with multiple logical operators', () => { - const kuery = - '(service.name:opbeans-* OR service.name:kibana) and (service.environment:production)'; - const kueryNode = fromKueryExpression(kuery); - expect(getKueryFields([kueryNode])).toEqual([ - 'service.name', - 'service.name', - 'service.environment', - ]); - }); - - it('do not return if kuery field is null', () => { - const kuery = 'opbean'; - const kueryNode = fromKueryExpression(kuery); - expect(getKueryFields([kueryNode])).toEqual([]); - }); -}); diff --git a/x-pack/plugins/observability_solution/apm/common/utils/get_kuery_fields.ts b/x-pack/plugins/observability_solution/apm/common/utils/get_kuery_fields.ts deleted file mode 100644 index 0318e5bf0fe20..0000000000000 --- a/x-pack/plugins/observability_solution/apm/common/utils/get_kuery_fields.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { KueryNode } from '@kbn/es-query'; -import { compact } from 'lodash'; - -export function getKueryFields(nodes: KueryNode[]): string[] { - const allFields = nodes - .map((node) => { - const { - arguments: [fieldNameArg], - } = node; - - if (fieldNameArg.type === 'function') { - return getKueryFields(node.arguments); - } - - return fieldNameArg.value; - }) - .flat(); - - return compact(allFields); -} diff --git a/x-pack/plugins/observability_solution/apm/public/components/alerting/ui_components/alert_details_app_section/failed_transaction_chart.tsx b/x-pack/plugins/observability_solution/apm/public/components/alerting/ui_components/alert_details_app_section/failed_transaction_chart.tsx index fae281c05b908..02273f0f43141 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/alerting/ui_components/alert_details_app_section/failed_transaction_chart.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/alerting/ui_components/alert_details_app_section/failed_transaction_chart.tsx @@ -6,12 +6,25 @@ */ /* Error Rate */ -import { EuiFlexItem, EuiPanel, EuiFlexGroup, EuiTitle, EuiIconTip } from '@elastic/eui'; +import React from 'react'; +import chroma from 'chroma-js'; +import { + EuiFlexItem, + EuiPanel, + EuiFlexGroup, + EuiTitle, + EuiIconTip, + RecursivePartial, + useEuiTheme, + transparentize, +} from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { BoolQuery } from '@kbn/es-query'; -import React from 'react'; -import { RecursivePartial } from '@elastic/eui'; +import { UI_SETTINGS } from '@kbn/data-plugin/public'; import { Theme } from '@elastic/charts'; +import { AlertActiveTimeRangeAnnotation, AlertAnnotation } from '@kbn/observability-alert-details'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { DEFAULT_DATE_FORMAT } from './constants'; import { useFetcher } from '../../../../hooks/use_fetcher'; import { ChartType } from '../../../shared/charts/helper/get_timeseries_color'; import * as get_timeseries_color from '../../../shared/charts/helper/get_timeseries_color'; @@ -22,6 +35,7 @@ import { yLabelFormat } from './helpers'; import { usePreferredDataSourceAndBucketSize } from '../../../../hooks/use_preferred_data_source_and_bucket_size'; import { ApmDocumentType } from '../../../../../common/document_type'; import { TransactionTypeSelect } from './transaction_type_select'; +import { ViewInAPMButton } from './view_in_apm_button'; type ErrorRate = APIReturnType<'GET /internal/apm/services/{serviceName}/transactions/charts/error_rate'>; @@ -50,6 +64,8 @@ function FailedTransactionChart({ timeZone, kuery = '', filters, + alertStart, + alertEnd, }: { transactionType: string; transactionTypes?: string[]; @@ -63,7 +79,13 @@ function FailedTransactionChart({ timeZone: string; kuery?: string; filters?: BoolQuery; + alertStart?: number; + alertEnd?: number; }) { + const { euiTheme } = useEuiTheme(); + const { + services: { uiSettings }, + } = useKibana(); const { currentPeriodColor: currentPeriodColorErrorRate } = get_timeseries_color.getTimeSeriesColor(ChartType.FAILED_TRANSACTION_RATE); @@ -127,6 +149,28 @@ function FailedTransactionChart({ }, ]; const showTransactionTypeSelect = setTransactionType && transactionTypes; + const getFailedTransactionChartAdditionalData = () => { + if (alertStart) { + return [ + , + , + ]; + } + }; return ( @@ -153,12 +197,28 @@ function FailedTransactionChart({ /> )} + + + + + + + )} + + + + + + + )} + + + + + + + + serviceNavigator.navigate({ + serviceName, + serviceOverviewTab: transactionName ? 'transactions' : undefined, + query: { + environment, + rangeFrom: from, + rangeTo: to, + kuery, + transactionName, + transactionType, + }, + }) + } + iconType="sortRight" + color="text" + > + + + ); +} diff --git a/x-pack/plugins/observability_solution/apm/public/components/shared/unified_search_bar/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/shared/unified_search_bar/index.tsx index a1b5b7b7557a1..4e86f331e520f 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/shared/unified_search_bar/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/shared/unified_search_bar/index.tsx @@ -6,7 +6,14 @@ */ import React, { useCallback, useEffect } from 'react'; import { i18n } from '@kbn/i18n'; -import { Filter, fromKueryExpression, Query, TimeRange, toElasticsearchQuery } from '@kbn/es-query'; +import { + Filter, + fromKueryExpression, + getKqlFieldNamesFromExpression, + Query, + TimeRange, + toElasticsearchQuery, +} from '@kbn/es-query'; import { useHistory, useLocation } from 'react-router-dom'; import deepEqual from 'fast-deep-equal'; import { useKibana } from '@kbn/kibana-react-plugin/public'; @@ -27,7 +34,6 @@ import { useLegacyUrlParams } from '../../../context/url_params_context/use_url_ import { clearCache } from '../../../services/rest/call_api'; import { useTimeRangeId } from '../../../context/time_range_id/use_time_range_id'; import { toBoolean, toNumber } from '../../../context/url_params_context/helpers'; -import { getKueryFields } from '../../../../common/utils/get_kuery_fields'; import { SearchQueryActions } from '../../../services/telemetry'; export const DEFAULT_REFRESH_INTERVAL = 60000; @@ -228,7 +234,7 @@ export function UnifiedSearchBar({ if (!res) { return; } - const kueryFields = getKueryFields([fromKueryExpression(query?.query as string)]); + const kueryFields = getKqlFieldNamesFromExpression(query?.query as string); const existingQueryParams = toQuery(location.search); const updatedQueryWithTime = { diff --git a/x-pack/plugins/observability_solution/apm/public/embeddable/alerting/alerting_failed_transactions_chart/chart.tsx b/x-pack/plugins/observability_solution/apm/public/embeddable/alerting/alerting_failed_transactions_chart/chart.tsx index c0c92f46f9603..6dbb8fcc3a446 100644 --- a/x-pack/plugins/observability_solution/apm/public/embeddable/alerting/alerting_failed_transactions_chart/chart.tsx +++ b/x-pack/plugins/observability_solution/apm/public/embeddable/alerting/alerting_failed_transactions_chart/chart.tsx @@ -6,6 +6,8 @@ */ import React from 'react'; +import moment from 'moment'; +import { ALERT_END } from '@kbn/rule-data-utils'; import FailedTransactionChart from '../../../components/alerting/ui_components/alert_details_app_section/failed_transaction_chart'; import { useAlertingProps } from '../use_alerting_props'; import { TimeRangeCallout } from '../time_range_callout'; @@ -15,6 +17,7 @@ import type { EmbeddableApmAlertingVizProps } from '../types'; export function APMAlertingFailedTransactionsChart({ rule, + alert, serviceName, environment = ENVIRONMENT_ALL.value, rangeFrom = 'now-15m', @@ -24,6 +27,7 @@ export function APMAlertingFailedTransactionsChart({ kuery = '', filters, }: EmbeddableApmAlertingVizProps) { + const alertEnd = alert.fields[ALERT_END] ? moment(alert.fields[ALERT_END]).valueOf() : undefined; const { transactionType: currentTransactionType, transactionTypes, @@ -61,6 +65,8 @@ export function APMAlertingFailedTransactionsChart({ timeZone={timeZone} kuery={kuery} filters={filters} + alertStart={alert.start} + alertEnd={alertEnd} /> ); } diff --git a/x-pack/plugins/observability_solution/apm/public/locator/helpers.ts b/x-pack/plugins/observability_solution/apm/public/locator/helpers.ts index 61ac0b75c50fb..69c041a00374c 100644 --- a/x-pack/plugins/observability_solution/apm/public/locator/helpers.ts +++ b/x-pack/plugins/observability_solution/apm/public/locator/helpers.ts @@ -33,7 +33,10 @@ export const APMLocatorPayloadValidator = t.union([ }), }), t.type({ - query: environmentRt, + query: t.intersection([ + environmentRt, + t.partial({ kuery: t.string, rangeFrom: t.string, rangeTo: t.string }), + ]), }), ]), ]); diff --git a/x-pack/plugins/observability_solution/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts b/x-pack/plugins/observability_solution/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts index 7bf03245d039e..13dddf6c33bdc 100644 --- a/x-pack/plugins/observability_solution/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts +++ b/x-pack/plugins/observability_solution/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts @@ -5,7 +5,7 @@ * 2.0. */ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { fromKueryExpression } from '@kbn/es-query'; +import { getKqlFieldNamesFromExpression } from '@kbn/es-query'; import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { createHash } from 'crypto'; import { flatten, merge, pickBy, sortBy, sum, uniq } from 'lodash'; @@ -54,7 +54,6 @@ import { SavedServiceGroup, } from '../../../../common/service_groups'; import { asMutableArray } from '../../../../common/utils/as_mutable_array'; -import { getKueryFields } from '../../../../common/utils/get_kuery_fields'; import { APMError } from '../../../../typings/es_schemas/ui/apm_error'; import { AgentName } from '../../../../typings/es_schemas/ui/fields/agent'; import { Span } from '../../../../typings/es_schemas/ui/span'; @@ -1409,11 +1408,10 @@ export const tasks: TelemetryTask[] = [ namespaces: ['*'], }); - const kueryNodes = response.saved_objects.map(({ attributes: { kuery } }) => - fromKueryExpression(kuery) - ); - - const kueryFields = getKueryFields(kueryNodes); + const kueryExpressions = response.saved_objects.map(({ attributes: { kuery } }) => kuery); + const kueryFields = kueryExpressions + .map(getKqlFieldNamesFromExpression) + .reduce((a, b) => a.concat(b), []); return { service_groups: { @@ -1435,11 +1433,12 @@ export const tasks: TelemetryTask[] = [ namespaces: ['*'], }); - const kueryNodes = response.saved_objects.map(({ attributes: { kuery } }) => - fromKueryExpression(kuery ?? '') + const kueryExpressions = response.saved_objects.map( + ({ attributes: { kuery } }) => kuery ?? '' ); - - const kueryFields = getKueryFields(kueryNodes); + const kueryFields = kueryExpressions + .map(getKqlFieldNamesFromExpression) + .reduce((a, b) => a.concat(b), []); return { custom_dashboards: { diff --git a/x-pack/plugins/observability_solution/infra/public/common/asset_details_config/asset_details_tabs.tsx b/x-pack/plugins/observability_solution/infra/public/common/asset_details_config/asset_details_tabs.tsx index 1383e1c49915e..c7f4b9f497a52 100644 --- a/x-pack/plugins/observability_solution/infra/public/common/asset_details_config/asset_details_tabs.tsx +++ b/x-pack/plugins/observability_solution/infra/public/common/asset_details_config/asset_details_tabs.tsx @@ -90,6 +90,13 @@ const dashboardsTab: Tab = { ), }; +const linkToApmTab: Tab = { + id: ContentTabIds.LINK_TO_APM, + name: i18n.translate('xpack.infra.assetDetails.tabs.linkToApm', { + defaultMessage: 'APM', + }), +}; + export const hostDetailsTabs: Tab[] = [ overviewTab, metadataTab, @@ -101,8 +108,11 @@ export const hostDetailsTabs: Tab[] = [ osqueryTab, dashboardsTab, ]; +export const hostDetailsFlyoutTabs: Tab[] = [...hostDetailsTabs, linkToApmTab]; + // Profiling and Logs tab would be added in next iteration export const containerDetailsTabs: Tab[] = [overviewTab, metadataTab]; +export const containerDetailsFlyoutTabs: Tab[] = [overviewTab, metadataTab, linkToApmTab]; export const getAssetDetailsTabs = (type: string): Tab[] => { switch (type) { @@ -114,3 +124,14 @@ export const getAssetDetailsTabs = (type: string): Tab[] => { return []; } }; + +export const getAssetDetailsFlyoutTabs = (type: string): Tab[] => { + switch (type) { + case 'host': + return hostDetailsFlyoutTabs; + case 'container': + return containerDetailsFlyoutTabs; + default: + return []; + } +}; diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/__stories__/decorator.tsx b/x-pack/plugins/observability_solution/infra/public/components/asset_details/__stories__/decorator.tsx index 5d75389d8d8c8..7a7f93a7c57f5 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/__stories__/decorator.tsx +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/__stories__/decorator.tsx @@ -152,6 +152,7 @@ export const DecorateWithKibanaContext: DecoratorFn = (story) => { telemetry: { reportAssetDetailsFlyoutViewed: () => {}, reportAssetDetailsPageViewed: () => {}, + reportAssetDashboardLoaded: () => {}, }, }; diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/constants.ts b/x-pack/plugins/observability_solution/infra/public/components/asset_details/constants.ts index 81a82ecb30875..49a174ba22c1c 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/constants.ts +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/constants.ts @@ -5,12 +5,18 @@ * 2.0. */ -import { INTEGRATION_NAME } from './types'; +import { INTEGRATION_NAME, ASSET_DETAILS_ASSET_TYPE } from './types'; export const ASSET_DETAILS_FLYOUT_COMPONENT_NAME = 'infraAssetDetailsFlyout'; export const ASSET_DETAILS_PAGE_COMPONENT_NAME = 'infraAssetDetailsPage'; export const APM_HOST_FILTER_FIELD = 'host.hostname'; +export const APM_CONTAINER_FILTER_FIELD = 'container.id'; + +export const APM_FILTER_FIELD_PER_ASSET_TYPE = { + [ASSET_DETAILS_ASSET_TYPE.container]: APM_CONTAINER_FILTER_FIELD, + [ASSET_DETAILS_ASSET_TYPE.host]: APM_HOST_FILTER_FIELD, +}; export const ASSET_DETAILS_URL_STATE_KEY = 'assetDetails'; diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_page_header.tsx b/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_page_header.tsx index 29c048c540a04..be98902ad9c57 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_page_header.tsx +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_page_header.tsx @@ -22,11 +22,11 @@ import { usePluginConfig } from '../../../containers/plugin_config_context'; import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; import { useProfilingIntegrationSetting } from '../../../hooks/use_profiling_integration_setting'; import { CreateAlertRuleButton } from '../../shared/alerts/links/create_alert_rule_button'; -import { APM_HOST_FILTER_FIELD } from '../constants'; import { LinkToNodeDetails } from '../links'; import { ContentTabIds, type LinkOptions, type RouteState, type Tab, type TabIds } from '../types'; import { useAssetDetailsRenderPropsContext } from './use_asset_details_render_props'; import { useTabSwitcherContext } from './use_tab_switcher'; +import { getApmField } from '../utils'; type TabItem = NonNullable['tabs']>[number]; @@ -157,7 +157,7 @@ const useTabs = (tabs: Tab[]) => { app: 'apm', hash: 'traces', search: { - kuery: `${APM_HOST_FILTER_FIELD}:"${asset.name}"`, + kuery: `${getApmField(asset.type)}:"${asset.id}"`, }, }); diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/dashboards/dashboards.tsx b/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/dashboards/dashboards.tsx index c326015bfebf9..e297c2e6a2191 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/dashboards/dashboards.tsx +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/dashboards/dashboards.tsx @@ -32,6 +32,8 @@ import { } from '@kbn/observability-shared-plugin/public'; import { useLocation } from 'react-router-dom'; import { decode } from '@kbn/rison'; +import { isEqual } from 'lodash'; +import type { AssetDashboardLoadedParams } from '../../../../services/telemetry/types'; import { useKibanaContextForPlugin } from '../../../../hooks/use_kibana'; import { buildAssetIdFilter } from '../../../../utils/filters/build'; import type { @@ -56,17 +58,39 @@ export function Dashboards() { const { asset, renderMode } = useAssetDetailsRenderPropsContext(); const location = useLocation(); const { - services: { share }, + services: { share, telemetry }, } = useKibanaContextForPlugin(); const [dashboard, setDashboard] = useState(); const [customDashboards, setCustomDashboards] = useState([]); const [currentDashboard, setCurrentDashboard] = useState(); + const [trackingEventProperties, setTrackingEventProperties] = useState({}); const { data: allAvailableDashboards, status } = useDashboardFetcher(); const { metrics } = useDataViewsContext(); const [urlState, setUrlState] = useAssetDetailsUrlState(); + const trackOnlyOnceTheSameDashboardFilters = React.useRef(false); const { dashboards, loading, reload } = useFetchCustomDashboards({ assetType: asset.type }); + useEffect(() => { + trackOnlyOnceTheSameDashboardFilters.current = false; + if (currentDashboard) { + const currentEventTrackingProperties: AssetDashboardLoadedParams = { + assetType: asset.type, + state: currentDashboard.dashboardFilterAssetIdEnabled, + filtered_by: currentDashboard.dashboardFilterAssetIdEnabled ? ['assetId'] : [], + }; + if (isEqual(trackingEventProperties, currentEventTrackingProperties)) { + trackOnlyOnceTheSameDashboardFilters.current = true; + return; + } + + setTrackingEventProperties(currentEventTrackingProperties); + if (!trackOnlyOnceTheSameDashboardFilters.current) { + telemetry.reportAssetDashboardLoaded(currentEventTrackingProperties); + } + } + }, [asset.type, currentDashboard, telemetry, trackingEventProperties]); + useEffect(() => { const allAvailableDashboardsMap = new Map(); allAvailableDashboards.forEach((availableDashboard) => { @@ -99,9 +123,11 @@ export function Dashboards() { } }, [ allAvailableDashboards, + asset.type, currentDashboard?.dashboardSavedObjectId, dashboards, setUrlState, + telemetry, urlState?.dashboardId, ]); diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/types.ts b/x-pack/plugins/observability_solution/infra/public/components/asset_details/types.ts index e51a7b53bda7d..35eea0faab44b 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/types.ts +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/types.ts @@ -102,3 +102,8 @@ export enum INTEGRATION_NAME { kubernetesContainer = 'kubernetesContainer', docker = 'docker', } + +export enum ASSET_DETAILS_ASSET_TYPE { + container = 'container', + host = 'host', +} diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/utils.ts b/x-pack/plugins/observability_solution/infra/public/components/asset_details/utils.ts index 1838e613e4402..6356b42fdf0bb 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/utils.ts +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/utils.ts @@ -5,8 +5,9 @@ * 2.0. */ +import type { InventoryItemType } from '@kbn/metrics-data-access-plugin/common'; import type { InfraMetadata } from '../../../common/http_api'; -import { INTEGRATIONS } from './constants'; +import { INTEGRATIONS, APM_FILTER_FIELD_PER_ASSET_TYPE } from './constants'; export const toTimestampRange = ({ from, to }: { from: string; to: string }) => { const fromTs = new Date(from).getTime(); @@ -34,3 +35,14 @@ export const getIntegrationsAvailable = (metadata?: InfraMetadata | null) => { .filter(([_, fields]) => metadata?.features?.some((f) => fields.includes(f.name))) .map(([name]) => name); }; + +export const getApmField = (assetType: InventoryItemType): string => { + switch (assetType) { + case 'host': + return APM_FILTER_FIELD_PER_ASSET_TYPE.host; + case 'container': + return APM_FILTER_FIELD_PER_ASSET_TYPE.container; + default: + return ''; + } +}; diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/components/nodes_overview.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/components/nodes_overview.tsx index 8830324f1ce45..62e2d1de5c935 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/components/nodes_overview.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/components/nodes_overview.tsx @@ -7,7 +7,7 @@ import { i18n } from '@kbn/i18n'; import { usePerformanceContext } from '@kbn/ebt-tools'; -import React, { useCallback } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { useCurrentEuiBreakpoint } from '@elastic/eui'; import { euiStyled } from '@kbn/kibana-react-plugin/common'; import { InventoryItemType } from '@kbn/metrics-data-access-plugin/common'; @@ -63,11 +63,20 @@ export const NodesOverview = ({ isAutoReloading, }: Props) => { const currentBreakpoint = useCurrentEuiBreakpoint(); - const [{ detailsItemId }, setFlyoutUrlState] = useAssetDetailsFlyoutState(); + const [{ detailsItemId, assetType }, setFlyoutUrlState] = useAssetDetailsFlyoutState(); const { onPageReady } = usePerformanceContext(); + const nodeName = useMemo( + () => nodes.find((node) => node.path[0].value === detailsItemId)?.name, + [detailsItemId, nodes] + ); + const closeFlyout = useCallback( - () => setFlyoutUrlState({ detailsItemId: null }), + () => + setFlyoutUrlState({ + detailsItemId: null, + assetType: null, + }), [setFlyoutUrlState] ); @@ -149,9 +158,10 @@ export const NodesOverview = ({ bottomMargin={bottomMargin} staticHeight={isStatic} /> - {nodeType === 'host' && detailsItemId && ( + {nodeType === assetType && detailsItemId && ( void; currentTime: number; @@ -24,20 +23,11 @@ interface Props { refreshInterval?: number; } -const flyoutTabs = [ - ...hostDetailsTabs, - { - id: ContentTabIds.LINK_TO_APM, - name: i18n.translate('xpack.infra.assetDetails.tabs.linkToApm', { - defaultMessage: 'APM', - }), - }, -]; - const ONE_HOUR = 60 * 60 * 1000; export const AssetDetailsFlyout = ({ assetName, + assetId, assetType, closeFlyout, currentTime, @@ -62,7 +52,7 @@ export const AssetDetailsFlyout = ({ return source ? ( { - if (nodeType === 'host') { - setFlyoutUrlState({ detailsItemId: node.name }); + if (nodeType === 'host' || showContainerAssetDetailPage) { + setFlyoutUrlState({ detailsItemId: node.id, assetType: nodeType }); } else { togglePopover(); } @@ -71,7 +77,7 @@ export const Node = ({ color={color} nodeName={node.name} value={value} - showBorder={detailsItemId === node.name || isPopoverOpen} + showBorder={detailsItemId === node.id || isPopoverOpen} /> ); diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/hooks/use_asset_details_flyout_url_state.ts b/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/hooks/use_asset_details_flyout_url_state.ts index 7847cfc0da268..10279312ed882 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/hooks/use_asset_details_flyout_url_state.ts +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/hooks/use_asset_details_flyout_url_state.ts @@ -13,6 +13,7 @@ import { useUrlState } from '../../../../utils/use_url_state'; export const GET_DEFAULT_PROPERTIES: AssetDetailsFlyoutProperties = { detailsItemId: null, + assetType: null, }; const ASSET_DETAILS_FLYOUT_URL_STATE_KEY = 'assetDetailsFlyout'; @@ -35,6 +36,7 @@ export const useAssetDetailsFlyoutState = (): [ const AssetDetailsFlyoutStateRT = rt.type({ detailsItemId: rt.union([rt.string, rt.null]), + assetType: rt.union([rt.string, rt.null]), }); export type AssetDetailsFlyoutState = rt.TypeOf; diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/settings/features_configuration_panel.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/settings/features_configuration_panel.tsx index f0d7e9d487277..d8df6ef8b39fa 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/settings/features_configuration_panel.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/settings/features_configuration_panel.tsx @@ -13,6 +13,7 @@ import React from 'react'; import { enableInfrastructureHostsView, enableInfrastructureProfilingIntegration, + enableInfrastructureAssetCustomDashboards, enableInfrastructureContainerAssetView, } from '@kbn/observability-plugin/common'; import { useEditableSettings } from '@kbn/observability-shared-plugin/public'; @@ -76,6 +77,12 @@ export function FeaturesConfigurationPanel({ onFieldChange={handleFieldChange} unsavedChange={unsavedChanges[enableInfrastructureHostsView]} /> + {featureFlags.profilingEnabled && ( => ({ reportAssetDetailsFlyoutViewed: jest.fn(), reportAssetDetailsPageViewed: jest.fn(), reportPerformanceMetricEvent: jest.fn(), + reportAssetDashboardLoaded: jest.fn(), }); diff --git a/x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts b/x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts index 2c8cac426635d..49c606419b702 100644 --- a/x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts +++ b/x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_client.ts @@ -8,6 +8,7 @@ import type { AnalyticsServiceSetup } from '@kbn/core-analytics-server'; import { reportPerformanceMetricEvent } from '@kbn/ebt-tools'; import { + AssetDashboardLoadedParams, AssetDetailsFlyoutViewedParams, AssetDetailsPageViewedParams, HostEntryClickedParams, @@ -73,6 +74,10 @@ export class TelemetryClient implements ITelemetryClient { this.analytics.reportEvent(InfraTelemetryEventTypes.ASSET_DETAILS_PAGE_VIEWED, params); }; + public reportAssetDashboardLoaded = (params: AssetDashboardLoadedParams) => { + this.analytics.reportEvent(InfraTelemetryEventTypes.ASSET_DASHBOARD_LOADED, params); + }; + public reportPerformanceMetricEvent = ( eventName: string, duration: number, diff --git a/x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_events.ts b/x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_events.ts index b83cbfe262e63..39b2389e71a44 100644 --- a/x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_events.ts +++ b/x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_events.ts @@ -187,6 +187,35 @@ const assetDetailsPageViewed: InfraTelemetryEvent = { }, }; +const assetDashboardLoaded: InfraTelemetryEvent = { + eventType: InfraTelemetryEventTypes.ASSET_DASHBOARD_LOADED, + schema: { + assetType: { + type: 'keyword', + _meta: { + description: 'Asset type for the selected asset.', + optional: false, + }, + }, + state: { + type: 'boolean', + _meta: { + description: 'If the dashboard is filtered or now', + optional: false, + }, + }, + filtered_by: { + type: 'array', + items: { + type: 'text', + _meta: { + description: 'Filters enabled for the dashboard added for an asset', + }, + }, + }, + }, +}; + export const infraTelemetryEvents = [ assetDetailsFlyoutViewed, assetDetailsPageViewed, @@ -195,4 +224,5 @@ export const infraTelemetryEvents = [ hostFlyoutRemoveFilter, hostFlyoutAddFilter, hostViewTotalHostCountRetrieved, + assetDashboardLoaded, ]; diff --git a/x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts b/x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts index 3fa8a9b447111..5862b20863ad5 100644 --- a/x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts +++ b/x-pack/plugins/observability_solution/infra/public/services/telemetry/telemetry_service.test.ts @@ -237,4 +237,28 @@ describe('TelemetryService', () => { ); }); }); + + describe('#reportAssetDashboardLoaded', () => { + it('should report asset details viewed in full page with properties', async () => { + const setupParams = getSetupParams(); + service.setup(setupParams); + const telemetry = service.start(); + + telemetry.reportAssetDashboardLoaded({ + assetType: 'host', + state: true, + filtered_by: ['assetId'], + }); + + expect(setupParams.analytics.reportEvent).toHaveBeenCalledTimes(1); + expect(setupParams.analytics.reportEvent).toHaveBeenCalledWith( + InfraTelemetryEventTypes.ASSET_DASHBOARD_LOADED, + { + assetType: 'host', + state: true, + filtered_by: ['assetId'], + } + ); + }); + }); }); diff --git a/x-pack/plugins/observability_solution/infra/public/services/telemetry/types.ts b/x-pack/plugins/observability_solution/infra/public/services/telemetry/types.ts index 0556b20af0fb4..16bdb5658f740 100644 --- a/x-pack/plugins/observability_solution/infra/public/services/telemetry/types.ts +++ b/x-pack/plugins/observability_solution/infra/public/services/telemetry/types.ts @@ -20,6 +20,7 @@ export enum InfraTelemetryEventTypes { HOST_VIEW_TOTAL_HOST_COUNT_RETRIEVED = 'Host View Total Host Count Retrieved', ASSET_DETAILS_FLYOUT_VIEWED = 'Asset Details Flyout Viewed', ASSET_DETAILS_PAGE_VIEWED = 'Asset Details Page Viewed', + ASSET_DASHBOARD_LOADED = 'Asset Dashboard Loaded', } export interface HostsViewQuerySubmittedParams { @@ -53,13 +54,19 @@ export interface AssetDetailsFlyoutViewedParams { export interface AssetDetailsPageViewedParams extends AssetDetailsFlyoutViewedParams { integrations?: string[]; } +export interface AssetDashboardLoadedParams { + state: boolean; + assetType: string; + filtered_by?: string[]; +} export type InfraTelemetryEventParams = | HostsViewQuerySubmittedParams | HostEntryClickedParams | HostFlyoutFilterActionParams | HostsViewQueryHostsCountRetrievedParams - | AssetDetailsFlyoutViewedParams; + | AssetDetailsFlyoutViewedParams + | AssetDashboardLoadedParams; export interface PerformanceMetricInnerEvents { key1?: string; @@ -80,6 +87,7 @@ export interface ITelemetryClient { innerEvents: PerformanceMetricInnerEvents, meta: Record ): void; + reportAssetDashboardLoaded(params: AssetDashboardLoadedParams): void; } export type InfraTelemetryEvent = @@ -110,4 +118,8 @@ export type InfraTelemetryEvent = | { eventType: InfraTelemetryEventTypes.ASSET_DETAILS_PAGE_VIEWED; schema: RootSchema; + } + | { + eventType: InfraTelemetryEventTypes.ASSET_DASHBOARD_LOADED; + schema: RootSchema; }; diff --git a/x-pack/plugins/observability_solution/observability/common/custom_threshold_rule/types.ts b/x-pack/plugins/observability_solution/observability/common/custom_threshold_rule/types.ts index 2633da58c2033..38b7e6d90061c 100644 --- a/x-pack/plugins/observability_solution/observability/common/custom_threshold_rule/types.ts +++ b/x-pack/plugins/observability_solution/observability/common/custom_threshold_rule/types.ts @@ -60,6 +60,7 @@ export enum AlertStates { // Types for the executor export interface CustomThresholdSearchSourceFields extends SerializedSearchSourceFields { query?: Query; + filter?: Array>; } export interface ThresholdParams { diff --git a/x-pack/plugins/observability_solution/observability/public/components/alerts_table/common/render_cell_value.tsx b/x-pack/plugins/observability_solution/observability/public/components/alerts_table/common/render_cell_value.tsx index 22289706784e7..6f6eb54a333d1 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/alerts_table/common/render_cell_value.tsx +++ b/x-pack/plugins/observability_solution/observability/public/components/alerts_table/common/render_cell_value.tsx @@ -20,6 +20,7 @@ import { ALERT_RULE_NAME, ALERT_RULE_CATEGORY, ALERT_START, + ALERT_RULE_EXECUTION_TIMESTAMP, } from '@kbn/rule-data-utils'; import { isEmpty } from 'lodash'; import type { TimelineNonEcsData } from '@kbn/timelines-plugin/common'; @@ -97,6 +98,7 @@ export const getRenderCellValue = ({ return ; case TIMESTAMP: case ALERT_START: + case ALERT_RULE_EXECUTION_TIMESTAMP: return ; case ALERT_DURATION: return asDuration(Number(value)); diff --git a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/validation.test.ts b/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/validation.test.ts index f1c5bc9576763..d4d68194a8492 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/validation.test.ts +++ b/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/components/validation.test.ts @@ -15,9 +15,7 @@ import { EQUATION_REGEX, validateCustomThreshold } from './validation'; const errorReason = 'this should appear as error reason'; jest.mock('@kbn/es-query', () => { - const actual = jest.requireActual('@kbn/es-query'); return { - ...actual, buildEsQuery: jest.fn(() => { // eslint-disable-next-line no-throw-literal throw { shortMessage: errorReason }; 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 b169f83739881..41127b2880233 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 @@ -125,12 +125,18 @@ export default function Expressions(props: Props) { const createdSearchSource = await data.search.searchSource.create( initialSearchConfiguration ); - setRuleParams('searchConfiguration', { - ...initialSearchConfiguration, - ...(ruleParams.searchConfiguration?.query && { - query: ruleParams.searchConfiguration.query, - }), - }); + setRuleParams( + 'searchConfiguration', + getSearchConfiguration( + { + ...initialSearchConfiguration, + ...(ruleParams.searchConfiguration?.query && { + query: ruleParams.searchConfiguration.query, + }), + }, + setParamsWarning + ) + ); setSearchSource(createdSearchSource); setDataView(createdSearchSource.getField('index')); @@ -232,7 +238,10 @@ export default function Expressions(props: Props) { const onFilterChange = useCallback( ({ query }: { query?: Query }) => { setParamsWarning(undefined); - setRuleParams('searchConfiguration', { ...ruleParams.searchConfiguration, query }); + setRuleParams( + 'searchConfiguration', + getSearchConfiguration({ ...ruleParams.searchConfiguration, query }, setParamsWarning) + ); }, [setRuleParams, ruleParams.searchConfiguration] ); @@ -442,13 +451,16 @@ export default function Expressions(props: Props) { query={ruleParams.searchConfiguration?.query} filters={ruleParams.searchConfiguration?.filter} onFiltersUpdated={(filter) => { - // Since rule params will be sent to the API as is, and we only need meta and query parameters to be - // saved in the rule's saved object, we filter extra fields here (such as $state). - const filters = filter.map(({ meta, query }) => ({ meta, query })); - setRuleParams('searchConfiguration', { - ...ruleParams.searchConfiguration, - filter: filters, - }); + setRuleParams( + 'searchConfiguration', + getSearchConfiguration( + { + ...ruleParams.searchConfiguration, + filter, + }, + setParamsWarning + ) + ); }} /> {errors.filterQuery && ( diff --git a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/helpers/get_search_configuration.test.ts b/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/helpers/get_search_configuration.test.ts index 734a31c7b8744..243f4ce197a66 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/helpers/get_search_configuration.test.ts +++ b/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/helpers/get_search_configuration.test.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { FilterStateStore } from '@kbn/es-query'; import { defaultQuery, getSearchConfiguration } from './get_search_configuration'; describe('getSearchConfiguration()', () => { @@ -37,4 +38,72 @@ describe('getSearchConfiguration()', () => { expect(getSearchConfiguration({ query }, onWarning)).toEqual({ query: defaultQuery }); expect(onWarning).toHaveBeenCalledTimes(1); }); + + it('should return filter without $state field WITHOUT query', () => { + const filter = [ + { + meta: { + alias: null, + disabled: false, + field: 'service.name', + index: 'dataset-logs-*-*', + key: 'service.name', + negate: false, + params: { + query: 'synth-node-0', + }, + type: 'phrase', + }, + query: { + match_phrase: { + 'service.name': 'synth-node-0', + }, + }, + $state: { + store: FilterStateStore.APP_STATE, + }, + }, + ]; + + expect(getSearchConfiguration({ filter }, onWarning)).toEqual({ + filter: filter.map((aFilter) => ({ meta: aFilter.meta, query: aFilter.query })), + }); + expect(onWarning).toHaveBeenCalledTimes(0); + }); + + it('should return filter without $state field WITH esql query', () => { + const filter = [ + { + meta: { + alias: null, + disabled: false, + field: 'service.name', + index: 'dataset-logs-*-*', + key: 'service.name', + negate: false, + params: { + query: 'synth-node-0', + }, + type: 'phrase', + }, + query: { + match_phrase: { + 'service.name': 'synth-node-0', + }, + }, + $state: { + store: FilterStateStore.APP_STATE, + }, + }, + ]; + const query = { + esql: 'random esql', + }; + + expect(getSearchConfiguration({ filter, query }, onWarning)).toEqual({ + filter: filter.map((aFilter) => ({ meta: aFilter.meta, query: aFilter.query })), + query: defaultQuery, + }); + expect(onWarning).toHaveBeenCalledTimes(1); + }); }); diff --git a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/helpers/get_search_configuration.ts b/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/helpers/get_search_configuration.ts index 9bdcd74a97804..ed1b3ae4db7d9 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/helpers/get_search_configuration.ts +++ b/x-pack/plugins/observability_solution/observability/public/components/custom_threshold/helpers/get_search_configuration.ts @@ -29,13 +29,27 @@ export const getSearchConfiguration = ( ): CustomThresholdSearchSourceFields => { if (fields.query && !isOfQueryType(fields.query)) { onWarning(searchConfigQueryWarning); - return { + return adjustSearchConfigurationFilter({ ...fields, query: defaultQuery, - }; + }); } - return { + return adjustSearchConfigurationFilter({ ...fields, query: fields.query, + }); +}; + +const adjustSearchConfigurationFilter = ( + searchConfiguration: CustomThresholdSearchSourceFields +): CustomThresholdSearchSourceFields => { + // Only meta and query fields are saved in the rule params, so we ignore other fields such as $state + const filter = searchConfiguration.filter + ? searchConfiguration.filter.map(({ meta, query }) => ({ meta, query })) + : undefined; + + return { + ...searchConfiguration, + filter, }; }; diff --git a/x-pack/plugins/observability_solution/observability/server/ui_settings.ts b/x-pack/plugins/observability_solution/observability/server/ui_settings.ts index 152d4dc00b905..30c829c999043 100644 --- a/x-pack/plugins/observability_solution/observability/server/ui_settings.ts +++ b/x-pack/plugins/observability_solution/observability/server/ui_settings.ts @@ -283,9 +283,9 @@ export const uiSettings: Record = { 'xpack.observability.enableInfrastructureAssetCustomDashboardsDescription', { defaultMessage: - '{betaLabel} Enable option to link custom dashboards in the asset details view.', + '{technicalPreviewLabel} Enable option to link custom dashboards in the asset details view.', values: { - betaLabel: `[${betaLabel}]`, + technicalPreviewLabel: `[${technicalPreviewLabel}]`, }, } ), diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/common/index.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/common/index.ts index dc8a9d46a7a06..e29aa4c2e1bc9 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/common/index.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/common/index.ts @@ -41,6 +41,7 @@ export { aiAssistantResponseLanguage, aiAssistantLogsIndexPattern, aiAssistantSimulatedFunctionCalling, + aiAssistantSearchConnectorIndexPattern, } from './ui_settings/settings_keys'; export { concatenateChatCompletionChunks } from './utils/concatenate_chat_completion_chunks'; diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/common/ui_settings/settings_keys.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/common/ui_settings/settings_keys.ts index a57611079b279..1f6d4d173cfa8 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/common/ui_settings/settings_keys.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/common/ui_settings/settings_keys.ts @@ -10,3 +10,5 @@ export const aiAssistantLogsIndexPattern = 'observability:aiAssistantLogsIndexPa export const aiAssistantResponseLanguage = 'observability:aiAssistantResponseLanguage'; export const aiAssistantSimulatedFunctionCalling = 'observability:aiAssistantSimulatedFunctionCalling'; +export const aiAssistantSearchConnectorIndexPattern = + 'observability:aiAssistantSearchConnectorIndexPattern'; diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/public/index.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/public/index.ts index 52d2511f9877f..e981e1ba15d89 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/public/index.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/public/index.ts @@ -82,6 +82,7 @@ export { aiAssistantResponseLanguage, aiAssistantLogsIndexPattern, aiAssistantSimulatedFunctionCalling, + aiAssistantSearchConnectorIndexPattern, } from '../common/ui_settings/settings_keys'; export const plugin: PluginInitializer< diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/index.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/index.ts index 344d46f557782..03b3f4ccdc766 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/index.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/index.ts @@ -22,6 +22,7 @@ export { aiAssistantResponseLanguage, aiAssistantLogsIndexPattern, aiAssistantSimulatedFunctionCalling, + aiAssistantSearchConnectorIndexPattern, } from '../common'; export { streamIntoObservable } from './service/util/stream_into_observable'; diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.test.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.test.ts index ed5f9a9ee044d..add345ffce9c5 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.test.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.test.ts @@ -5,7 +5,7 @@ * 2.0. */ import type { ActionsClient } from '@kbn/actions-plugin/server/actions_client'; -import type { ElasticsearchClient, Logger } from '@kbn/core/server'; +import type { ElasticsearchClient, IUiSettingsClient, Logger } from '@kbn/core/server'; import type { DeeplyMockedKeys } from '@kbn/utility-types-jest'; import { waitFor } from '@testing-library/react'; import { last, merge, repeat } from 'lodash'; @@ -94,6 +94,10 @@ describe('Observability AI Assistant client', () => { get: jest.fn(), } as any; + const uiSettingsClientMock: DeeplyMockedKeys = { + get: jest.fn(), + } as any; + const internalUserEsClientMock: DeeplyMockedKeys = { search: jest.fn(), index: jest.fn(), @@ -172,6 +176,7 @@ describe('Observability AI Assistant client', () => { return new ObservabilityAIAssistantClient({ actionsClient: actionsClientMock, + uiSettingsClient: uiSettingsClientMock, esClient: { asInternalUser: internalUserEsClientMock, asCurrentUser: currentUserEsClientMock, diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.ts index 0dc38698faa89..485beb7033d21 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/client/index.ts @@ -7,7 +7,7 @@ import type { SearchHit } from '@elastic/elasticsearch/lib/api/types'; import { notFound } from '@hapi/boom'; import type { ActionsClient } from '@kbn/actions-plugin/server'; -import type { ElasticsearchClient } from '@kbn/core/server'; +import type { ElasticsearchClient, IUiSettingsClient } from '@kbn/core/server'; import type { Logger } from '@kbn/logging'; import type { PublicMethodsOf } from '@kbn/utility-types'; import { merge, omit } from 'lodash'; @@ -80,6 +80,7 @@ export class ObservabilityAIAssistantClient { constructor( private readonly dependencies: { actionsClient: PublicMethodsOf; + uiSettingsClient: IUiSettingsClient; namespace: string; esClient: { asInternalUser: ElasticsearchClient; @@ -659,6 +660,7 @@ export class ObservabilityAIAssistantClient { queries, categories, asCurrentUser: this.dependencies.esClient.asCurrentUser, + uiSettingsClient: this.dependencies.uiSettingsClient, }); }; diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/index.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/index.ts index 31249f8f6d40f..318cf83b54373 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/index.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/index.ts @@ -276,12 +276,15 @@ export class ObservabilityAIAssistantService { // user will not be found when executed from system connector context const user = plugins.security.authc.getCurrentUser(request); + const soClient = coreStart.savedObjects.getScopedClient(request); + const basePath = coreStart.http.basePath.get(request); const { spaceId } = getSpaceIdFromPath(basePath, coreStart.http.basePath.serverBasePath); return new ObservabilityAIAssistantClient({ actionsClient: await plugins.actions.getActionsClientWithRequest(request), + uiSettingsClient: coreStart.uiSettings.asScopedToClient(soClient), namespace: spaceId, esClient: { asInternalUser: coreStart.elasticsearch.client.asInternalUser, diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/knowledge_base_service/index.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/knowledge_base_service/index.ts index e0ba8bd48d478..04493f9af2dde 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/knowledge_base_service/index.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/knowledge_base_service/index.ts @@ -6,14 +6,15 @@ */ import { errors } from '@elastic/elasticsearch'; import { serverUnavailable, gatewayTimeout } from '@hapi/boom'; -import type { ElasticsearchClient } from '@kbn/core/server'; +import type { ElasticsearchClient, IUiSettingsClient } from '@kbn/core/server'; import type { Logger } from '@kbn/logging'; import type { TaskManagerStartContract } from '@kbn/task-manager-plugin/server'; import pLimit from 'p-limit'; import pRetry from 'p-retry'; -import { map, orderBy } from 'lodash'; +import { isEmpty, map, orderBy } from 'lodash'; import { encode } from 'gpt-tokenizer'; import { MlTrainedModelDeploymentNodesStats } from '@elastic/elasticsearch/lib/api/types'; +import { aiAssistantSearchConnectorIndexPattern } from '../../../common'; import { INDEX_QUEUED_DOCUMENTS_TASK_ID, INDEX_QUEUED_DOCUMENTS_TASK_TYPE } from '..'; import { KnowledgeBaseEntry, KnowledgeBaseEntryRole, UserInstruction } from '../../../common/types'; import type { ObservabilityAIAssistantResourceNames } from '../types'; @@ -347,19 +348,55 @@ export class KnowledgeBaseService { })); } + private async getConnectorIndices( + client: ElasticsearchClient, + uiSettingsClient: IUiSettingsClient + ) { + // improve performance by running this in parallel with the `uiSettingsClient` request + const responsePromise = client.transport.request({ + method: 'GET', + path: '_connector', + querystring: { + filter_path: 'results.index_name', + }, + }); + + const customSearchConnectorIndex = await uiSettingsClient.get( + aiAssistantSearchConnectorIndexPattern + ); + + if (customSearchConnectorIndex) { + return customSearchConnectorIndex.split(','); + } + + const response = (await responsePromise) as { results: Array<{ index_name: string }> }; + const connectorIndices = response.results.map((result) => result.index_name); + + // preserve backwards compatibility with 8.14 (may not be needed in the future) + if (isEmpty(connectorIndices)) { + return ['search-*']; + } + + return connectorIndices; + } + private async recallFromConnectors({ queries, asCurrentUser, + uiSettingsClient, modelId, }: { queries: string[]; asCurrentUser: ElasticsearchClient; + uiSettingsClient: IUiSettingsClient; modelId: string; }): Promise { const ML_INFERENCE_PREFIX = 'ml.inference.'; + const connectorIndices = await this.getConnectorIndices(asCurrentUser, uiSettingsClient); + const fieldCaps = await asCurrentUser.fieldCaps({ - index: 'search*', + index: connectorIndices, fields: `${ML_INFERENCE_PREFIX}*`, allow_no_indices: true, types: ['sparse_vector'], @@ -404,7 +441,7 @@ export class KnowledgeBaseService { }); const response = await asCurrentUser.search({ - index: 'search-*', + index: connectorIndices, query: { bool: { should: esQueries, @@ -416,12 +453,14 @@ export class KnowledgeBaseService { }, }); - return response.hits.hits.map((hit) => ({ + const results = response.hits.hits.map((hit) => ({ text: JSON.stringify(hit._source), score: hit._score!, is_correction: false, id: hit._id, })); + + return results; } recall = async ({ @@ -430,12 +469,14 @@ export class KnowledgeBaseService { categories, namespace, asCurrentUser, + uiSettingsClient, }: { queries: string[]; categories?: string[]; user?: { name: string }; namespace: string; asCurrentUser: ElasticsearchClient; + uiSettingsClient: IUiSettingsClient; }): Promise<{ entries: RecalledEntry[]; }> => { @@ -457,6 +498,7 @@ export class KnowledgeBaseService { }), this.recallFromConnectors({ asCurrentUser, + uiSettingsClient, queries, modelId, }).catch((error) => { diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_management/common/ui_settings.ts b/x-pack/plugins/observability_solution/observability_ai_assistant_management/common/ui_settings.ts index d6a6db84d1084..682e66385d56b 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_management/common/ui_settings.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_management/common/ui_settings.ts @@ -12,6 +12,7 @@ import { aiAssistantLogsIndexPattern, aiAssistantResponseLanguage, aiAssistantSimulatedFunctionCalling, + aiAssistantSearchConnectorIndexPattern, } from '@kbn/observability-ai-assistant-plugin/common'; import { DEFAULT_LANGUAGE_OPTION, @@ -85,4 +86,22 @@ export const uiSettings: Record = { type: 'boolean', requiresPageReload: true, }, + [aiAssistantSearchConnectorIndexPattern]: { + category: ['observability'], + name: i18n.translate( + 'xpack.observabilityAiAssistantManagement.settingsTab.h3.searchConnectorIndexPatternLabel', + { defaultMessage: 'Search connector index pattern' } + ), + value: '', + description: i18n.translate( + 'xpack.observabilityAiAssistantManagement.settingsPage.searchConnectorIndexPatternDescription', + { + defaultMessage: + 'Index pattern used by the AI Assistant when querying search connectors indices (part of the knowledge base). By default the index for every search connector will be queried', + } + ), + schema: schema.string(), + type: 'string', + requiresPageReload: true, + }, }; diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_management/public/routes/components/settings_tab/ui_settings.tsx b/x-pack/plugins/observability_solution/observability_ai_assistant_management/public/routes/components/settings_tab/ui_settings.tsx index 9621e77b6e675..d366a07240822 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_management/public/routes/components/settings_tab/ui_settings.tsx +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_management/public/routes/components/settings_tab/ui_settings.tsx @@ -11,6 +11,7 @@ import { aiAssistantLogsIndexPattern, aiAssistantResponseLanguage, aiAssistantSimulatedFunctionCalling, + aiAssistantSearchConnectorIndexPattern, } from '@kbn/observability-ai-assistant-plugin/public'; import { FieldRow, FieldRowProvider } from '@kbn/management-settings-components-field-row'; import { EuiSpacer } from '@elastic/eui'; @@ -22,6 +23,7 @@ const settingsKeys = [ aiAssistantLogsIndexPattern, aiAssistantResponseLanguage, aiAssistantSimulatedFunctionCalling, + aiAssistantSearchConnectorIndexPattern, ]; export function UISettings() { diff --git a/x-pack/plugins/observability_solution/slo/public/components/slo/burn_rate/alert_details/components/custom_panels/apm/apm_alert_details.tsx b/x-pack/plugins/observability_solution/slo/public/components/slo/burn_rate/alert_details/components/custom_panels/apm/apm_alert_details.tsx index 86893aa0fb87e..4d1ff0d532fba 100644 --- a/x-pack/plugins/observability_solution/slo/public/components/slo/burn_rate/alert_details/components/custom_panels/apm/apm_alert_details.tsx +++ b/x-pack/plugins/observability_solution/slo/public/components/slo/burn_rate/alert_details/components/custom_panels/apm/apm_alert_details.tsx @@ -6,22 +6,26 @@ */ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import React from 'react'; -import { GetSLOResponse, APMTransactionDurationIndicator } from '@kbn/slo-schema'; -import { APMEmbeddableRoot } from './embeddable_root'; +import { + APMEmbeddableRoot, + APMTransactionDurationSLOResponse, + APMErrorRateSLOResponse, +} from './embeddable_root'; import type { BurnRateRule, BurnRateAlert, TimeRange } from '../../../types'; -interface APMAlertDetailsProps { - slo: APMTransactionDurationSLOResponse; +interface APMAlertDetailsProps { + slo: IndicatorType; alert: BurnRateAlert; rule: BurnRateRule; dataTimeRange: TimeRange; } -export type APMTransactionDurationSLOResponse = GetSLOResponse & { - indicator: APMTransactionDurationIndicator; -}; - -export function APMAlertDetails({ slo, dataTimeRange, alert, rule }: APMAlertDetailsProps) { +export function APMLatencyAlertDetails({ + slo, + dataTimeRange, + alert, + rule, +}: APMAlertDetailsProps) { return ( ); } + +export function APMAvailabilityAlertDetails({ + slo, + dataTimeRange, + alert, + rule, +}: APMAlertDetailsProps) { + return ( + + + + + + + + + + + + ); +} diff --git a/x-pack/plugins/observability_solution/slo/public/components/slo/burn_rate/alert_details/components/custom_panels/apm/embeddable_root.tsx b/x-pack/plugins/observability_solution/slo/public/components/slo/burn_rate/alert_details/components/custom_panels/apm/embeddable_root.tsx index 535ba2e94e67c..c7f95d788e676 100644 --- a/x-pack/plugins/observability_solution/slo/public/components/slo/burn_rate/alert_details/components/custom_panels/apm/embeddable_root.tsx +++ b/x-pack/plugins/observability_solution/slo/public/components/slo/burn_rate/alert_details/components/custom_panels/apm/embeddable_root.tsx @@ -8,7 +8,12 @@ import React from 'react'; import { v4 as uuidv4 } from 'uuid'; import { buildQueryFromFilters, Filter } from '@kbn/es-query'; import { ReactEmbeddableRenderer } from '@kbn/embeddable-plugin/public'; -import { GetSLOResponse, APMTransactionDurationIndicator } from '@kbn/slo-schema'; +import { + GetSLOResponse, + apmTransactionDurationIndicatorSchema, + APMTransactionDurationIndicator, + APMTransactionErrorRateIndicator, +} from '@kbn/slo-schema'; import type { BurnRateAlert, BurnRateRule, TimeRange } from '../../../types'; type EmbeddableId = @@ -18,18 +23,22 @@ type EmbeddableId = | 'APM_ALERTING_LATENCY_CHART_EMBEDDABLE' | 'APM_ALERTING_THROUGHPUT_CHART_EMBEDDABLE'; +export type APMTransactionDurationSLOResponse = GetSLOResponse & { + indicator: APMTransactionDurationIndicator; +}; + +export type APMErrorRateSLOResponse = GetSLOResponse & { + indicator: APMTransactionErrorRateIndicator; +}; + interface APMEmbeddableRootProps { - slo: APMTransactionDurationSLOResponse; + slo: APMTransactionDurationSLOResponse | APMErrorRateSLOResponse; dataTimeRange: TimeRange; embeddableId: EmbeddableId; alert: BurnRateAlert; rule: BurnRateRule; } -export type APMTransactionDurationSLOResponse = GetSLOResponse & { - indicator: APMTransactionDurationIndicator; -}; - export function APMEmbeddableRoot({ slo, dataTimeRange, @@ -40,6 +49,7 @@ export function APMEmbeddableRoot({ const filter = slo.indicator.params.filter; const isKueryFilter = typeof filter === 'string'; const groupingInput = getInputFromGroupings(slo); + const indicator = slo.indicator; const kuery = isKueryFilter ? filter : undefined; const allFilters = @@ -48,7 +58,7 @@ export function APMEmbeddableRoot({ : groupingInput.filters; const filters = buildQueryFromFilters(allFilters, undefined, undefined); const groupingsInput = getInputFromGroupings(slo); - const { transactionName, transactionType, environment, service } = slo.indicator.params; + const { transactionName, transactionType, environment, service } = indicator.params; const input = { id: uuidv4(), serviceName: service, @@ -57,7 +67,9 @@ export function APMEmbeddableRoot({ environment: environment !== '*' ? environment : undefined, rangeFrom: dataTimeRange.from.toISOString(), rangeTo: dataTimeRange.to.toISOString(), - latencyThresholdInMicroseconds: slo.indicator.params.threshold * 1000, + latencyThresholdInMicroseconds: apmTransactionDurationIndicatorSchema.is(indicator) + ? indicator.params.threshold * 1000 + : undefined, kuery, filters, alert, @@ -70,13 +82,15 @@ export function APMEmbeddableRoot({ return ( ({ getSerializedStateForChild: () => ({ rawState: input }) })} hidePanelChrome={true} /> ); } -const getInputFromGroupings = (slo: APMTransactionDurationSLOResponse) => { +const getInputFromGroupings = ( + slo: APMTransactionDurationSLOResponse | APMErrorRateSLOResponse +) => { const groupings = Object.entries(slo.groupings) as Array<[string, string]>; const input: { transactionName?: string; diff --git a/x-pack/plugins/observability_solution/slo/public/components/slo/burn_rate/alert_details/components/custom_panels/custom_panels.tsx b/x-pack/plugins/observability_solution/slo/public/components/slo/burn_rate/alert_details/components/custom_panels/custom_panels.tsx index 534c037ff3540..e22cb7cd5a3fb 100644 --- a/x-pack/plugins/observability_solution/slo/public/components/slo/burn_rate/alert_details/components/custom_panels/custom_panels.tsx +++ b/x-pack/plugins/observability_solution/slo/public/components/slo/burn_rate/alert_details/components/custom_panels/custom_panels.tsx @@ -7,11 +7,14 @@ import React from 'react'; import type { GetSLOResponse } from '@kbn/slo-schema'; -import { APMAlertDetails } from './apm/apm_alert_details'; +import { APMLatencyAlertDetails, APMAvailabilityAlertDetails } from './apm/apm_alert_details'; import { CustomKqlPanels } from './custom_kql/custom_kql_panels'; import { getDataTimeRange } from '../../utils/time_range'; import type { BurnRateAlert, BurnRateRule } from '../../types'; -import type { APMTransactionDurationSLOResponse } from './apm/apm_alert_details'; +import type { + APMTransactionDurationSLOResponse, + APMErrorRateSLOResponse, +} from './apm/embeddable_root'; interface Props { alert: BurnRateAlert; @@ -26,13 +29,22 @@ export function CustomAlertDetailsPanel({ slo, alert, rule }: Props) { return ; case 'sli.apm.transactionDuration': return ( - ); + case 'sli.apm.transactionErrorRate': + return ( + + ); default: return null; } diff --git a/x-pack/plugins/observability_solution/slo/public/context/plugin_context.tsx b/x-pack/plugins/observability_solution/slo/public/context/plugin_context.tsx index 6b8a36655f70d..b61ccb8085a12 100644 --- a/x-pack/plugins/observability_solution/slo/public/context/plugin_context.tsx +++ b/x-pack/plugins/observability_solution/slo/public/context/plugin_context.tsx @@ -20,10 +20,4 @@ export interface PluginContextValue { experimentalFeatures?: ExperimentalFeatures; } -export interface OverviewEmbeddableContextValue { - observabilityRuleTypeRegistry: ObservabilityRuleTypeRegistry; -} - -export const OverviewEmbeddableContext = createContext(null); - export const PluginContext = createContext(null); diff --git a/x-pack/plugins/observability_solution/slo/public/embeddable/slo/common/slo_embeddable_context.tsx b/x-pack/plugins/observability_solution/slo/public/embeddable/slo/common/slo_embeddable_context.tsx new file mode 100644 index 0000000000000..acb0897b07e71 --- /dev/null +++ b/x-pack/plugins/observability_solution/slo/public/embeddable/slo/common/slo_embeddable_context.tsx @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { Router } from '@kbn/shared-ux-router'; +import { createBrowserHistory } from 'history'; +import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common'; +import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { PluginContext } from '../../../context/plugin_context'; +import { SloEmbeddableDeps } from '../overview/types'; + +const queryClient = new QueryClient(); + +export interface SloEmbeddableContextProps { + deps: SloEmbeddableDeps; + children: React.ReactNode; +} + +export function SloEmbeddableContext({ deps, children }: SloEmbeddableContextProps) { + const { observabilityRuleTypeRegistry } = deps.observability; + const { navigation } = deps.observabilityShared; + + return ( + + + + + {children} + + + + + ); +} diff --git a/x-pack/plugins/observability_solution/slo/public/embeddable/slo/overview/slo_embeddable_factory.tsx b/x-pack/plugins/observability_solution/slo/public/embeddable/slo/overview/slo_embeddable_factory.tsx index e0cf5d0b13837..33252386c0e81 100644 --- a/x-pack/plugins/observability_solution/slo/public/embeddable/slo/overview/slo_embeddable_factory.tsx +++ b/x-pack/plugins/observability_solution/slo/public/embeddable/slo/overview/slo_embeddable_factory.tsx @@ -9,7 +9,6 @@ import { i18n } from '@kbn/i18n'; import React, { useEffect } from 'react'; import styled from 'styled-components'; import { EuiFlexItem, EuiLink, EuiFlexGroup } from '@elastic/eui'; -import { Router } from '@kbn/shared-ux-router'; import { ReactEmbeddableFactory } from '@kbn/embeddable-plugin/public'; import { initializeTitles, @@ -17,10 +16,6 @@ import { fetch$, } from '@kbn/presentation-publishing'; import { BehaviorSubject, Subject } from 'rxjs'; -import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common'; -import { createBrowserHistory } from 'history'; import { CONTEXT_MENU_TRIGGER } from '@kbn/embeddable-plugin/public'; import { ActionExecutionContext } from '@kbn/ui-actions-plugin/public'; import { SLO_OVERVIEW_EMBEDDABLE_ID } from './constants'; @@ -34,9 +29,8 @@ import { GroupSloCustomInput, } from './types'; import { EDIT_SLO_OVERVIEW_ACTION } from '../../../ui_actions/edit_slo_overview_panel'; -import { OverviewEmbeddableContext } from '../../../context/plugin_context'; +import { SloEmbeddableContext } from '../common/slo_embeddable_context'; -const queryClient = new QueryClient(); export const getOverviewPanelTitle = () => i18n.translate('xpack.slo.sloEmbeddable.displayName', { defaultMessage: 'SLO Overview', @@ -123,7 +117,6 @@ export const getOverviewEmbeddableFactory = (deps: SloEmbeddableDeps) => { groupFilters$, remoteName$ ); - const { observabilityRuleTypeRegistry } = deps.observability; useEffect(() => { return () => { @@ -188,21 +181,9 @@ export const getOverviewEmbeddableFactory = (deps: SloEmbeddableDeps) => { } }; return ( - - - - - - {showAllGroupByInstances ? ( - - ) : ( - renderOverview() - )} - - - - - + + {showAllGroupByInstances ? : renderOverview()} + ); }, }; diff --git a/x-pack/plugins/observability_solution/slo/public/embeddable/slo/overview/types.ts b/x-pack/plugins/observability_solution/slo/public/embeddable/slo/overview/types.ts index f23b986c02950..8773fba3e0998 100644 --- a/x-pack/plugins/observability_solution/slo/public/embeddable/slo/overview/types.ts +++ b/x-pack/plugins/observability_solution/slo/public/embeddable/slo/overview/types.ts @@ -20,6 +20,7 @@ import { } from '@kbn/core/public'; import { ObservabilityPublicStart } from '@kbn/observability-plugin/public'; import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; +import { ObservabilitySharedPluginStart } from '@kbn/observability-shared-plugin/public'; export type OverviewMode = 'single' | 'groups'; export type GroupBy = 'slo.tags' | 'status' | 'slo.indicator.type'; @@ -77,6 +78,7 @@ export interface SloEmbeddableDeps { application: ApplicationStart; notifications: NotificationsStart; observability: ObservabilityPublicStart; + observabilityShared: ObservabilitySharedPluginStart; uiActions: UiActionsStart; } diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slos/components/card_view/slo_card_item.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slos/components/card_view/slo_card_item.tsx index ebdc068435a76..0808298b24a8b 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slos/components/card_view/slo_card_item.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slos/components/card_view/slo_card_item.tsx @@ -74,7 +74,6 @@ const getFirstGroupBy = (slo: SLOWithSummaryResponse) => { export function SloCardItem({ slo, rules, activeAlerts, historicalSummary, refetchRules }: Props) { const containerRef = React.useRef(null); - const [isMouseOver, setIsMouseOver] = useState(false); const [isActionsPopoverOpen, setIsActionsPopoverOpen] = useState(false); const [isAddRuleFlyoutOpen, setIsAddRuleFlyoutOpen] = useState(false); const [isEditRuleFlyoutOpen, setIsEditRuleFlyoutOpen] = useState(false); @@ -110,21 +109,25 @@ export function SloCardItem({ slo, rules, activeAlerts, historicalSummary, refet } - onMouseOver={() => { - if (!isMouseOver) { - setIsMouseOver(true); - } - }} - onMouseLeave={() => { - if (isMouseOver) { - setIsMouseOver(false); - } - }} paddingSize="none" css={css` height: 182px; overflow: hidden; position: relative; + + & .sloCardItemActions_hover { + pointer-events: none; + opacity: 0; + + &:focus-within { + pointer-events: auto; + opacity: 1; + } + } + &:hover .sloCardItemActions_hover { + pointer-events: auto; + opacity: 1; + } `} title={ slo.summary.summaryUpdatedAt @@ -151,7 +154,7 @@ export function SloCardItem({ slo, rules, activeAlerts, historicalSummary, refet /> } /> - {(isMouseOver || isActionsPopoverOpen) && ( +
- )} +
- setItemsPerPage(perPage)} - /> + {total > 0 && total > itemsPerPage ? ( + { + setPage(0); + setItemsPerPage(perPage); + }} + /> + ) : null} )} diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slos/components/grouped_slos/group_view.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slos/components/grouped_slos/group_view.tsx index 207be28bf7264..ffe7c1ede95b2 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slos/components/grouped_slos/group_view.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slos/components/grouped_slos/group_view.tsx @@ -93,7 +93,7 @@ export function GroupView({ /> ))} - {total > 0 ? ( + {total > 0 && total > perPage ? ( { - onStateChange({ perPage: newPerPage }); + onStateChange({ perPage: newPerPage, page: 0 }); }} /> diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slos/components/slo_list.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slos/components/slo_list.tsx index be10b99ae5531..49e49f09169bf 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slos/components/slo_list.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slos/components/slo_list.tsx @@ -98,7 +98,7 @@ export function SloList() { error={isError} sloView={view} /> - {total > 0 ? ( + {total > 0 && total > perPage ? ( { - onStateChange({ perPage: newPerPage }); + onStateChange({ perPage: newPerPage, page: 0 }); }} /> diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slos/components/slos_overview/slos_overview.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slos/components/slos_overview/slos_overview.tsx index c3c234e0f98a5..ab551637a6f25 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slos/components/slos_overview/slos_overview.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slos/components/slos_overview/slos_overview.tsx @@ -24,13 +24,14 @@ import { OverViewItem } from './overview_item'; export function SLOsOverview() { const { state } = useUrlSearchState(); - const { kqlQuery, filters, tagsFilter, statusFilter } = state; + const { kqlQuery, filters, tagsFilter, statusFilter, lastRefresh } = state; const { data, isLoading } = useFetchSLOsOverview({ kqlQuery, filters, tagsFilter, statusFilter, + lastRefresh, }); const theme = useEuiTheme().euiTheme; diff --git a/x-pack/plugins/observability_solution/slo/server/services/__snapshots__/historical_summary_client.test.ts.snap b/x-pack/plugins/observability_solution/slo/server/services/__snapshots__/historical_summary_client.test.ts.snap index 2759ac43d2149..3b495e56db593 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/__snapshots__/historical_summary_client.test.ts.snap +++ b/x-pack/plugins/observability_solution/slo/server/services/__snapshots__/historical_summary_client.test.ts.snap @@ -9423,6 +9423,146 @@ Object { `; exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 1`] = ` +Object { + "date": Any, + "errorBudget": Object { + "consumed": 0.55648, + "initial": 0.05, + "isEstimated": false, + "remaining": 0.44352, + }, + "sliValue": 0.972176, + "status": "HEALTHY", +} +`; + +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 2`] = ` +Object { + "date": Any, + "errorBudget": Object { + "consumed": 0.5574, + "initial": 0.05, + "isEstimated": false, + "remaining": 0.4426, + }, + "sliValue": 0.97213, + "status": "HEALTHY", +} +`; + +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 3`] = ` +Object { + "date": Any, + "errorBudget": Object { + "consumed": 0.55834, + "initial": 0.05, + "isEstimated": false, + "remaining": 0.44166, + }, + "sliValue": 0.972083, + "status": "HEALTHY", +} +`; + +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 4`] = ` +Object { + "date": Any, + "errorBudget": Object { + "consumed": 0.55926, + "initial": 0.05, + "isEstimated": false, + "remaining": 0.44074, + }, + "sliValue": 0.972037, + "status": "HEALTHY", +} +`; + +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 5`] = ` +Object { + "date": Any, + "errorBudget": Object { + "consumed": 0.56018, + "initial": 0.05, + "isEstimated": false, + "remaining": 0.43982, + }, + "sliValue": 0.971991, + "status": "HEALTHY", +} +`; + +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 6`] = ` +Object { + "date": Any, + "errorBudget": Object { + "consumed": 0.56112, + "initial": 0.05, + "isEstimated": false, + "remaining": 0.43888, + }, + "sliValue": 0.971944, + "status": "HEALTHY", +} +`; + +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 7`] = ` +Object { + "date": Any, + "errorBudget": Object { + "consumed": 0.56204, + "initial": 0.05, + "isEstimated": false, + "remaining": 0.43796, + }, + "sliValue": 0.971898, + "status": "HEALTHY", +} +`; + +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 8`] = ` +Object { + "date": Any, + "errorBudget": Object { + "consumed": 0.56296, + "initial": 0.05, + "isEstimated": false, + "remaining": 0.43704, + }, + "sliValue": 0.971852, + "status": "HEALTHY", +} +`; + +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 9`] = ` +Object { + "date": Any, + "errorBudget": Object { + "consumed": 0.56388, + "initial": 0.05, + "isEstimated": false, + "remaining": 0.43612, + }, + "sliValue": 0.971806, + "status": "HEALTHY", +} +`; + +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 10`] = ` +Object { + "date": Any, + "errorBudget": Object { + "consumed": 0.56482, + "initial": 0.05, + "isEstimated": false, + "remaining": 0.43518, + }, + "sliValue": 0.971759, + "status": "HEALTHY", +} +`; + +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 11`] = ` Object { "date": Any, "errorBudget": Object { @@ -9436,7 +9576,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 2`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 12`] = ` Object { "date": Any, "errorBudget": Object { @@ -9450,7 +9590,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 3`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 13`] = ` Object { "date": Any, "errorBudget": Object { @@ -9464,7 +9604,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 4`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 14`] = ` Object { "date": Any, "errorBudget": Object { @@ -9478,7 +9618,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 5`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 15`] = ` Object { "date": Any, "errorBudget": Object { @@ -9492,7 +9632,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 6`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 16`] = ` Object { "date": Any, "errorBudget": Object { @@ -9506,7 +9646,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 7`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 17`] = ` Object { "date": Any, "errorBudget": Object { @@ -9520,7 +9660,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 8`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 18`] = ` Object { "date": Any, "errorBudget": Object { @@ -9534,7 +9674,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 9`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 19`] = ` Object { "date": Any, "errorBudget": Object { @@ -9548,7 +9688,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 10`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 20`] = ` Object { "date": Any, "errorBudget": Object { @@ -9562,7 +9702,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 11`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 21`] = ` Object { "date": Any, "errorBudget": Object { @@ -9576,7 +9716,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 12`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 22`] = ` Object { "date": Any, "errorBudget": Object { @@ -9590,7 +9730,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 13`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 23`] = ` Object { "date": Any, "errorBudget": Object { @@ -9604,7 +9744,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 14`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 24`] = ` Object { "date": Any, "errorBudget": Object { @@ -9618,7 +9758,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 15`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 25`] = ` Object { "date": Any, "errorBudget": Object { @@ -9632,7 +9772,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 16`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 26`] = ` Object { "date": Any, "errorBudget": Object { @@ -9646,7 +9786,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 17`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 27`] = ` Object { "date": Any, "errorBudget": Object { @@ -9660,7 +9800,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 18`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 28`] = ` Object { "date": Any, "errorBudget": Object { @@ -9674,7 +9814,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 19`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 29`] = ` Object { "date": Any, "errorBudget": Object { @@ -9688,7 +9828,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 20`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 30`] = ` Object { "date": Any, "errorBudget": Object { @@ -9702,7 +9842,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 21`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 31`] = ` Object { "date": Any, "errorBudget": Object { @@ -9716,7 +9856,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 22`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 32`] = ` Object { "date": Any, "errorBudget": Object { @@ -9730,7 +9870,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 23`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 33`] = ` Object { "date": Any, "errorBudget": Object { @@ -9744,7 +9884,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 24`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 34`] = ` Object { "date": Any, "errorBudget": Object { @@ -9758,7 +9898,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 25`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 35`] = ` Object { "date": Any, "errorBudget": Object { @@ -9772,7 +9912,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 26`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 36`] = ` Object { "date": Any, "errorBudget": Object { @@ -9786,7 +9926,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 27`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 37`] = ` Object { "date": Any, "errorBudget": Object { @@ -9800,7 +9940,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 28`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 38`] = ` Object { "date": Any, "errorBudget": Object { @@ -9814,7 +9954,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 29`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 39`] = ` Object { "date": Any, "errorBudget": Object { @@ -9828,7 +9968,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 30`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 40`] = ` Object { "date": Any, "errorBudget": Object { @@ -9842,7 +9982,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 31`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 41`] = ` Object { "date": Any, "errorBudget": Object { @@ -9856,7 +9996,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 32`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 42`] = ` Object { "date": Any, "errorBudget": Object { @@ -9870,7 +10010,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 33`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 43`] = ` Object { "date": Any, "errorBudget": Object { @@ -9884,7 +10024,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 34`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 44`] = ` Object { "date": Any, "errorBudget": Object { @@ -9898,7 +10038,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 35`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 45`] = ` Object { "date": Any, "errorBudget": Object { @@ -9912,7 +10052,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 36`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 46`] = ` Object { "date": Any, "errorBudget": Object { @@ -9926,7 +10066,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 37`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 47`] = ` Object { "date": Any, "errorBudget": Object { @@ -9940,7 +10080,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 38`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 48`] = ` Object { "date": Any, "errorBudget": Object { @@ -9954,7 +10094,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 39`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 49`] = ` Object { "date": Any, "errorBudget": Object { @@ -9968,7 +10108,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 40`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 50`] = ` Object { "date": Any, "errorBudget": Object { @@ -9982,7 +10122,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 41`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 51`] = ` Object { "date": Any, "errorBudget": Object { @@ -9996,7 +10136,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 42`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 52`] = ` Object { "date": Any, "errorBudget": Object { @@ -10010,7 +10150,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 43`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 53`] = ` Object { "date": Any, "errorBudget": Object { @@ -10024,7 +10164,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 44`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 54`] = ` Object { "date": Any, "errorBudget": Object { @@ -10038,7 +10178,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 45`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 55`] = ` Object { "date": Any, "errorBudget": Object { @@ -10052,7 +10192,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 46`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 56`] = ` Object { "date": Any, "errorBudget": Object { @@ -10066,7 +10206,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 47`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 57`] = ` Object { "date": Any, "errorBudget": Object { @@ -10080,7 +10220,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 48`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 58`] = ` Object { "date": Any, "errorBudget": Object { @@ -10094,7 +10234,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 49`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 59`] = ` Object { "date": Any, "errorBudget": Object { @@ -10108,7 +10248,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 50`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 60`] = ` Object { "date": Any, "errorBudget": Object { @@ -10122,7 +10262,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 51`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 61`] = ` Object { "date": Any, "errorBudget": Object { @@ -10136,7 +10276,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 52`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 62`] = ` Object { "date": Any, "errorBudget": Object { @@ -10150,7 +10290,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 53`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 63`] = ` Object { "date": Any, "errorBudget": Object { @@ -10164,7 +10304,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 54`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 64`] = ` Object { "date": Any, "errorBudget": Object { @@ -10178,7 +10318,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 55`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 65`] = ` Object { "date": Any, "errorBudget": Object { @@ -10192,7 +10332,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 56`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 66`] = ` Object { "date": Any, "errorBudget": Object { @@ -10206,7 +10346,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 57`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 67`] = ` Object { "date": Any, "errorBudget": Object { @@ -10220,7 +10360,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 58`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 68`] = ` Object { "date": Any, "errorBudget": Object { @@ -10234,7 +10374,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 59`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 69`] = ` Object { "date": Any, "errorBudget": Object { @@ -10248,7 +10388,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 60`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 70`] = ` Object { "date": Any, "errorBudget": Object { @@ -10262,7 +10402,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 61`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 71`] = ` Object { "date": Any, "errorBudget": Object { @@ -10276,7 +10416,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 62`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 72`] = ` Object { "date": Any, "errorBudget": Object { @@ -10290,7 +10430,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 63`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 73`] = ` Object { "date": Any, "errorBudget": Object { @@ -10304,7 +10444,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 64`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 74`] = ` Object { "date": Any, "errorBudget": Object { @@ -10318,7 +10458,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 65`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 75`] = ` Object { "date": Any, "errorBudget": Object { @@ -10332,7 +10472,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 66`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 76`] = ` Object { "date": Any, "errorBudget": Object { @@ -10346,7 +10486,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 67`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 77`] = ` Object { "date": Any, "errorBudget": Object { @@ -10360,7 +10500,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 68`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 78`] = ` Object { "date": Any, "errorBudget": Object { @@ -10374,7 +10514,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 69`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 79`] = ` Object { "date": Any, "errorBudget": Object { @@ -10388,7 +10528,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 70`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 80`] = ` Object { "date": Any, "errorBudget": Object { @@ -10402,7 +10542,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 71`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 81`] = ` Object { "date": Any, "errorBudget": Object { @@ -10416,7 +10556,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 72`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 82`] = ` Object { "date": Any, "errorBudget": Object { @@ -10430,7 +10570,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 73`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 83`] = ` Object { "date": Any, "errorBudget": Object { @@ -10444,7 +10584,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 74`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 84`] = ` Object { "date": Any, "errorBudget": Object { @@ -10458,7 +10598,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 75`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 85`] = ` Object { "date": Any, "errorBudget": Object { @@ -10472,7 +10612,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 76`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 86`] = ` Object { "date": Any, "errorBudget": Object { @@ -10486,7 +10626,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 77`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 87`] = ` Object { "date": Any, "errorBudget": Object { @@ -10500,7 +10640,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 78`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 88`] = ` Object { "date": Any, "errorBudget": Object { @@ -10514,7 +10654,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 79`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 89`] = ` Object { "date": Any, "errorBudget": Object { @@ -10528,7 +10668,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 80`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 90`] = ` Object { "date": Any, "errorBudget": Object { @@ -10542,7 +10682,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 81`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 91`] = ` Object { "date": Any, "errorBudget": Object { @@ -10556,7 +10696,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 82`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 92`] = ` Object { "date": Any, "errorBudget": Object { @@ -10570,7 +10710,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 83`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 93`] = ` Object { "date": Any, "errorBudget": Object { @@ -10584,7 +10724,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 84`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 94`] = ` Object { "date": Any, "errorBudget": Object { @@ -10598,7 +10738,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 85`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 95`] = ` Object { "date": Any, "errorBudget": Object { @@ -10612,7 +10752,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 86`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 96`] = ` Object { "date": Any, "errorBudget": Object { @@ -10626,7 +10766,7 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 87`] = ` +exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 97`] = ` Object { "date": Any, "errorBudget": Object { @@ -10640,146 +10780,6 @@ Object { } `; -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 88`] = ` -Object { - "date": Any, - "errorBudget": Object { - "consumed": 0.6463, - "initial": 0.05, - "isEstimated": false, - "remaining": 0.3537, - }, - "sliValue": 0.967685, - "status": "HEALTHY", -} -`; - -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 89`] = ` -Object { - "date": Any, - "errorBudget": Object { - "consumed": 0.64722, - "initial": 0.05, - "isEstimated": false, - "remaining": 0.35278, - }, - "sliValue": 0.967639, - "status": "HEALTHY", -} -`; - -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 90`] = ` -Object { - "date": Any, - "errorBudget": Object { - "consumed": 0.64814, - "initial": 0.05, - "isEstimated": false, - "remaining": 0.35186, - }, - "sliValue": 0.967593, - "status": "HEALTHY", -} -`; - -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 91`] = ` -Object { - "date": Any, - "errorBudget": Object { - "consumed": 0.64908, - "initial": 0.05, - "isEstimated": false, - "remaining": 0.35092, - }, - "sliValue": 0.967546, - "status": "HEALTHY", -} -`; - -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 92`] = ` -Object { - "date": Any, - "errorBudget": Object { - "consumed": 0.65, - "initial": 0.05, - "isEstimated": false, - "remaining": 0.35, - }, - "sliValue": 0.9675, - "status": "HEALTHY", -} -`; - -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 93`] = ` -Object { - "date": Any, - "errorBudget": Object { - "consumed": 0.65092, - "initial": 0.05, - "isEstimated": false, - "remaining": 0.34908, - }, - "sliValue": 0.967454, - "status": "HEALTHY", -} -`; - -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 94`] = ` -Object { - "date": Any, - "errorBudget": Object { - "consumed": 0.65186, - "initial": 0.05, - "isEstimated": false, - "remaining": 0.34814, - }, - "sliValue": 0.967407, - "status": "HEALTHY", -} -`; - -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 95`] = ` -Object { - "date": Any, - "errorBudget": Object { - "consumed": 0.65278, - "initial": 0.05, - "isEstimated": false, - "remaining": 0.34722, - }, - "sliValue": 0.967361, - "status": "HEALTHY", -} -`; - -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 96`] = ` -Object { - "date": Any, - "errorBudget": Object { - "consumed": 0.6537, - "initial": 0.05, - "isEstimated": false, - "remaining": 0.3463, - }, - "sliValue": 0.967315, - "status": "HEALTHY", -} -`; - -exports[`FetchHistoricalSummary Rolling and Timeslices SLOs returns the summary using the provided date range 97`] = ` -Object { - "date": Any, - "errorBudget": Object { - "consumed": 0.65462, - "initial": 0.05, - "isEstimated": false, - "remaining": 0.34538, - }, - "sliValue": 0.967269, - "status": "HEALTHY", -} -`; - exports[`FetchHistoricalSummary filters with the 'instanceId' when provided 1`] = ` Object { "date": Any, diff --git a/x-pack/plugins/observability_solution/slo/server/services/historical_summary_client.test.ts b/x-pack/plugins/observability_solution/slo/server/services/historical_summary_client.test.ts index 939b240f5d88f..d01d0f654bf54 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/historical_summary_client.test.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/historical_summary_client.test.ts @@ -46,7 +46,7 @@ const generateEsResponseForRollingSLO = (slo: SLODefinition, overridedRange?: Da ? rollingDurationInDays + overridedRangeInDays : rollingDurationInDays * 2; const numberOfBuckets = fullDuration * bucketsPerDay; - const startDay = moment().subtract(fullDuration, 'day').startOf('day'); + const startRange = moment().subtract(fullDuration, 'day').startOf('minute'); const bucketSizeInHour = moment .duration( fixedInterval.slice(0, -1), @@ -67,11 +67,11 @@ const generateEsResponseForRollingSLO = (slo: SLODefinition, overridedRange?: Da buckets: Array(numberOfBuckets) .fill(0) .map((_, index) => ({ - key_as_string: startDay + key_as_string: startRange .clone() .add(index * bucketSizeInHour, 'hours') .toISOString(), - key: startDay + key: startRange .clone() .add(index * bucketSizeInHour, 'hours') .format('x'), diff --git a/x-pack/plugins/observability_solution/slo/server/services/historical_summary_client.ts b/x-pack/plugins/observability_solution/slo/server/services/historical_summary_client.ts index 263111c944da3..3389783a41ef0 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/historical_summary_client.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/historical_summary_client.ts @@ -410,7 +410,7 @@ function getDateRange( queryRange: { from: moment(range.from) .subtract(timeWindow.duration.value, unit) - .startOf('day') + .startOf('minute') .toDate(), to: moment(range.to).startOf('minute').toDate(), }, @@ -420,14 +420,14 @@ function getDateRange( const now = moment(); return { range: { - from: now.clone().subtract(timeWindow.duration.value, unit).startOf('day').toDate(), + from: now.clone().subtract(timeWindow.duration.value, unit).startOf('minute').toDate(), to: now.clone().startOf('minute').toDate(), }, queryRange: { from: now .clone() .subtract(timeWindow.duration.value * 2, unit) - .startOf('day') + .startOf('minute') .toDate(), to: now.clone().startOf('minute').toDate(), }, diff --git a/x-pack/plugins/osquery/cypress/e2e/all/saved_queries.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/saved_queries.cy.ts index 6638567a92625..27fe443eed062 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/saved_queries.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/saved_queries.cy.ts @@ -76,7 +76,8 @@ describe('ALL - Saved queries', { tags: ['@ess', '@serverless'] }, () => { }); }); - describe('prebuilt', () => { + // FAILING ES SERVERLESS PROMOTION: https://github.com/elastic/kibana/issues/169787 + describe.skip('prebuilt', () => { let packName: string; let packId: string; let savedQueryId: string; diff --git a/x-pack/plugins/reporting/server/config/index.ts b/x-pack/plugins/reporting/server/config/index.ts index 59f60f35cb717..4129717c6d791 100644 --- a/x-pack/plugins/reporting/server/config/index.ts +++ b/x-pack/plugins/reporting/server/config/index.ts @@ -24,6 +24,7 @@ export const config: PluginConfigDescriptor = { }, schema: ConfigSchema, deprecations: ({ unused }) => [ + unused('queue.indexInterval', { level: 'warning' }), // unused since 8.15 unused('capture.browser.chromium.maxScreenshotDimension', { level: 'warning' }), // unused since 7.8 unused('capture.browser.type', { level: 'warning' }), unused('poll.jobCompletionNotifier.intervalErrorMultiplier', { level: 'warning' }), // unused since 7.10 diff --git a/x-pack/plugins/reporting/server/deprecations/index.ts b/x-pack/plugins/reporting/server/deprecations/index.ts index 651defbb5d688..bca439532b3b0 100644 --- a/x-pack/plugins/reporting/server/deprecations/index.ts +++ b/x-pack/plugins/reporting/server/deprecations/index.ts @@ -20,7 +20,7 @@ export const registerDeprecations = ({ core.deprecations.registerDeprecations({ getDeprecations: async (ctx) => { return [ - ...(await getIlmPolicyDeprecationsInfo(ctx, { reportingCore })), + ...(await getIlmPolicyDeprecationsInfo(ctx)), ...(await getReportingRoleDeprecationsInfo(ctx, { reportingCore })), ]; }, diff --git a/x-pack/plugins/reporting/server/deprecations/migrate_existing_indices_ilm_policy.test.ts b/x-pack/plugins/reporting/server/deprecations/migrate_existing_indices_ilm_policy.test.ts index 9f0a10b861adb..233626d1b7b4c 100644 --- a/x-pack/plugins/reporting/server/deprecations/migrate_existing_indices_ilm_policy.test.ts +++ b/x-pack/plugins/reporting/server/deprecations/migrate_existing_indices_ilm_policy.test.ts @@ -7,10 +7,6 @@ import type { GetDeprecationsContext } from '@kbn/core/server'; import { elasticsearchServiceMock, savedObjectsClientMock } from '@kbn/core/server/mocks'; -import { createMockConfigSchema } from '@kbn/reporting-mocks-server'; - -import { ReportingCore } from '../core'; -import { createMockReportingCore } from '../test_helpers'; import { getDeprecationsInfo } from './migrate_existing_indices_ilm_policy'; @@ -21,12 +17,10 @@ type ScopedClusterClientMock = ReturnType< describe("Migrate existing indices' ILM policy deprecations", () => { let esClient: ScopedClusterClientMock; let deprecationsCtx: GetDeprecationsContext; - let reportingCore: ReportingCore; beforeEach(async () => { esClient = elasticsearchServiceMock.createScopedClusterClient(); deprecationsCtx = { esClient, savedObjectsClient: savedObjectsClientMock.create() }; - reportingCore = await createMockReportingCore(createMockConfigSchema()); }); const createIndexSettings = (lifecycleName: string) => ({ @@ -47,7 +41,7 @@ describe("Migrate existing indices' ILM policy deprecations", () => { indexB: createIndexSettings('kibana-reporting'), }); - expect(await getDeprecationsInfo(deprecationsCtx, { reportingCore })).toMatchInlineSnapshot(` + expect(await getDeprecationsInfo(deprecationsCtx)).toMatchInlineSnapshot(` Array [ Object { "correctiveActions": Object { @@ -60,7 +54,7 @@ describe("Migrate existing indices' ILM policy deprecations", () => { ], }, "level": "warning", - "message": "New reporting indices will be managed by the \\"kibana-reporting\\" provisioned ILM policy. You must edit this policy to manage the report lifecycle. This change targets all indices prefixed with \\".reporting-*\\".", + "message": "New reporting indices will be managed by the \\"kibana-reporting\\" provisioned ILM policy. You must edit this policy to manage the report lifecycle. This change targets the hidden system index pattern \\".kibana-reporting*\\".", "title": "Found reporting indices managed by custom ILM policy.", }, ] @@ -73,14 +67,10 @@ describe("Migrate existing indices' ILM policy deprecations", () => { indexB: createIndexSettings('kibana-reporting'), }); - expect(await getDeprecationsInfo(deprecationsCtx, { reportingCore })).toMatchInlineSnapshot( - `Array []` - ); + expect(await getDeprecationsInfo(deprecationsCtx)).toMatchInlineSnapshot(`Array []`); esClient.asInternalUser.indices.getSettings.mockResponse({}); - expect(await getDeprecationsInfo(deprecationsCtx, { reportingCore })).toMatchInlineSnapshot( - `Array []` - ); + expect(await getDeprecationsInfo(deprecationsCtx)).toMatchInlineSnapshot(`Array []`); }); }); diff --git a/x-pack/plugins/reporting/server/deprecations/migrate_existing_indices_ilm_policy.ts b/x-pack/plugins/reporting/server/deprecations/migrate_existing_indices_ilm_policy.ts index 2fcba6c0ccf53..fce6e6475d76e 100644 --- a/x-pack/plugins/reporting/server/deprecations/migrate_existing_indices_ilm_policy.ts +++ b/x-pack/plugins/reporting/server/deprecations/migrate_existing_indices_ilm_policy.ts @@ -8,24 +8,14 @@ import { DeprecationsDetails, GetDeprecationsContext } from '@kbn/core/server'; import { i18n } from '@kbn/i18n'; import { ILM_POLICY_NAME, INTERNAL_ROUTES } from '@kbn/reporting-common'; -import { ReportingCore } from '../core'; -import { deprecations } from '../lib/deprecations'; +import { REPORTING_DATA_STREAM_WILDCARD } from '@kbn/reporting-server'; +import { IlmPolicyManager } from '../lib/store'; -interface ExtraDependencies { - reportingCore: ReportingCore; -} - -export const getDeprecationsInfo = async ( - { esClient }: GetDeprecationsContext, - { reportingCore }: ExtraDependencies -): Promise => { - const store = await reportingCore.getStore(); - const indexPattern = store.getReportingIndexPattern(); - - const migrationStatus = await deprecations.checkIlmMigrationStatus({ - reportingCore, - elasticsearchClient: esClient.asInternalUser, - }); +export const getDeprecationsInfo = async ({ + esClient, +}: GetDeprecationsContext): Promise => { + const ilmPolicyManager = IlmPolicyManager.create({ client: esClient.asInternalUser }); + const migrationStatus = await ilmPolicyManager.checkIlmMigrationStatus(); if (migrationStatus !== 'ok') { return [ @@ -35,10 +25,10 @@ export const getDeprecationsInfo = async ( }), level: 'warning', message: i18n.translate('xpack.reporting.deprecations.migrateIndexIlmPolicyActionMessage', { - defaultMessage: `New reporting indices will be managed by the "{reportingIlmPolicy}" provisioned ILM policy. You must edit this policy to manage the report lifecycle. This change targets all indices prefixed with "{indexPattern}".`, + defaultMessage: `New reporting indices will be managed by the "{reportingIlmPolicy}" provisioned ILM policy. You must edit this policy to manage the report lifecycle. This change targets the hidden system index pattern "{indexPattern}".`, values: { reportingIlmPolicy: ILM_POLICY_NAME, - indexPattern, + indexPattern: REPORTING_DATA_STREAM_WILDCARD, }, }), correctiveActions: { diff --git a/x-pack/plugins/reporting/server/lib/content_stream.test.ts b/x-pack/plugins/reporting/server/lib/content_stream.test.ts index d4f179c5c9359..165c06baa579b 100644 --- a/x-pack/plugins/reporting/server/lib/content_stream.test.ts +++ b/x-pack/plugins/reporting/server/lib/content_stream.test.ts @@ -122,12 +122,12 @@ describe('ContentStream', () => { 'body.query.constant_score.filter.bool.must.0.term._id', 'something' ); - expect(request2).toHaveProperty('index', 'somewhere'); + expect(request2).toHaveProperty('index', '.reporting-*,.kibana-reporting*'); expect(request2).toHaveProperty( 'body.query.constant_score.filter.bool.must.0.term.parent_id', 'something' ); - expect(request3).toHaveProperty('index', 'somewhere'); + expect(request3).toHaveProperty('index', '.reporting-*,.kibana-reporting*'); expect(request3).toHaveProperty( 'body.query.constant_score.filter.bool.must.0.term.parent_id', 'something' @@ -293,8 +293,11 @@ describe('ContentStream', () => { 1, expect.objectContaining({ id: expect.any(String), - index: 'somewhere', + index: '.kibana-reporting', + op_type: 'create', + refresh: 'wait_for', body: { + '@timestamp': '1970-01-01T00:00:00.000Z', parent_id: 'something', output: { content: '34', @@ -307,8 +310,11 @@ describe('ContentStream', () => { 2, expect.objectContaining({ id: expect.any(String), - index: 'somewhere', + index: '.kibana-reporting', + op_type: 'create', + refresh: 'wait_for', body: { + '@timestamp': '1970-01-01T00:00:00.000Z', parent_id: 'something', output: { content: '56', @@ -335,9 +341,12 @@ describe('ContentStream', () => { 1, expect.objectContaining({ id: expect.any(String), - index: 'somewhere', + index: '.kibana-reporting', + op_type: 'create', + refresh: 'wait_for', body: { parent_id: 'something', + '@timestamp': '1970-01-01T00:00:00.000Z', output: { content: Buffer.from('456').toString('base64'), chunk: 1, @@ -349,9 +358,12 @@ describe('ContentStream', () => { 2, expect.objectContaining({ id: expect.any(String), - index: 'somewhere', + index: '.kibana-reporting', + op_type: 'create', + refresh: 'wait_for', body: { parent_id: 'something', + '@timestamp': '1970-01-01T00:00:00.000Z', output: { content: Buffer.from('78').toString('base64'), chunk: 2, diff --git a/x-pack/plugins/reporting/server/lib/content_stream.ts b/x-pack/plugins/reporting/server/lib/content_stream.ts index 17362516d2c9d..b3c113dd43c3b 100644 --- a/x-pack/plugins/reporting/server/lib/content_stream.ts +++ b/x-pack/plugins/reporting/server/lib/content_stream.ts @@ -8,9 +8,13 @@ import { Duplex } from 'stream'; import { v4 as uuidv4 } from 'uuid'; -import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import type { estypes } from '@elastic/elasticsearch'; import type { ElasticsearchClient, Logger } from '@kbn/core/server'; import type { ReportSource } from '@kbn/reporting-common/types'; +import { + REPORTING_DATA_STREAM_ALIAS, + REPORTING_DATA_STREAM_WILDCARD_WITH_LEGACY, +} from '@kbn/reporting-server'; import type { ReportingCore } from '..'; const ONE_MB = 1024 * 1024; @@ -31,6 +35,7 @@ interface ChunkOutput { } interface ChunkSource { + '@timestamp': string; parent_id: string; output: ChunkOutput; } @@ -90,7 +95,7 @@ export class ContentStream extends Duplex { private async readHead() { const { id, index } = this.document; - const body: SearchRequest['body'] = { + const body: SearchRequest = { _source: { includes: ['output.content', 'output.size', 'jobtype'] }, query: { constant_score: { @@ -110,13 +115,14 @@ export class ContentStream extends Duplex { const hits = response?.hits?.hits?.[0]; this.jobSize = hits?._source?.output?.size; + this.logger.debug(`Reading job of size ${this.jobSize}`); return hits?._source?.output?.content; } private async readChunk() { - const { id, index } = this.document; - const body: SearchRequest['body'] = { + const { id } = this.document; + const body: SearchRequest = { _source: { includes: ['output.content'] }, query: { constant_score: { @@ -132,7 +138,10 @@ export class ContentStream extends Duplex { this.logger.debug(`Reading chunk #${this.chunksRead}.`); - const response = await this.client.search({ body, index }); + const response = await this.client.search({ + body, + index: REPORTING_DATA_STREAM_WILDCARD_WITH_LEGACY, + }); const hits = response?.hits?.hits?.[0]; return hits?._source?.output.content; @@ -179,10 +188,11 @@ export class ContentStream extends Duplex { } private async writeHead(content: string) { - this.logger.debug(`Updating report contents.`); + this.logger.debug(`Updating chunk #0 (${this.document.id}).`); const body = await this.client.update({ ...this.document, + refresh: 'wait_for', body: { doc: { output: { content }, @@ -194,16 +204,19 @@ export class ContentStream extends Duplex { } private async writeChunk(content: string) { - const { id: parentId, index } = this.document; + const { id: parentId } = this.document; const id = uuidv4(); this.logger.debug(`Writing chunk #${this.chunksWritten} (${id}).`); await this.client.index({ id, - index, + index: REPORTING_DATA_STREAM_ALIAS, + refresh: 'wait_for', + op_type: 'create', body: { parent_id: parentId, + '@timestamp': new Date(0).toISOString(), // required for data streams compatibility output: { content, chunk: this.chunksWritten, diff --git a/x-pack/plugins/reporting/server/lib/deprecations/check_ilm_migration_status.ts b/x-pack/plugins/reporting/server/lib/deprecations/check_ilm_migration_status.ts deleted file mode 100644 index aab4c1f0cecf4..0000000000000 --- a/x-pack/plugins/reporting/server/lib/deprecations/check_ilm_migration_status.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { IlmPolicyMigrationStatus } from '@kbn/reporting-common/url'; -import { ILM_POLICY_NAME } from '@kbn/reporting-common'; -import { IlmPolicyManager } from '../store/ilm_policy_manager'; -import type { DeprecationsDependencies } from './types'; - -export const checkIlmMigrationStatus = async ({ - reportingCore, - elasticsearchClient, -}: DeprecationsDependencies): Promise => { - const ilmPolicyManager = IlmPolicyManager.create({ client: elasticsearchClient }); - if (!(await ilmPolicyManager.doesIlmPolicyExist())) { - return 'policy-not-found'; - } - - const store = await reportingCore.getStore(); - const indexPattern = store.getReportingIndexPattern(); - - const reportingIndicesSettings = await elasticsearchClient.indices.getSettings({ - index: indexPattern, - }); - - const hasUnmanagedIndices = Object.values(reportingIndicesSettings).some((settings) => { - return ( - settings?.settings?.index?.lifecycle?.name !== ILM_POLICY_NAME && - settings?.settings?.['index.lifecycle']?.name !== ILM_POLICY_NAME - ); - }); - - return hasUnmanagedIndices ? 'indices-not-managed-by-policy' : 'ok'; -}; diff --git a/x-pack/plugins/reporting/server/lib/deprecations/index.ts b/x-pack/plugins/reporting/server/lib/deprecations/index.ts index 2ddc46663600f..a4d1ee919e1cc 100644 --- a/x-pack/plugins/reporting/server/lib/deprecations/index.ts +++ b/x-pack/plugins/reporting/server/lib/deprecations/index.ts @@ -9,7 +9,6 @@ import { errors } from '@elastic/elasticsearch'; import Boom from '@hapi/boom'; import { i18n } from '@kbn/i18n'; import { DeprecationsDetails, DocLinksServiceSetup } from '@kbn/core/server'; -import { checkIlmMigrationStatus } from './check_ilm_migration_status'; function deprecationError( title: string, @@ -83,7 +82,6 @@ function getDetailedErrorMessage(error: any): string { } export const deprecations = { - checkIlmMigrationStatus, deprecationError, getDetailedErrorMessage, getErrorStatusCode, diff --git a/x-pack/plugins/reporting/server/lib/deprecations/types.ts b/x-pack/plugins/reporting/server/lib/deprecations/types.ts index 6df429d2b2ed9..5f572f89911ef 100644 --- a/x-pack/plugins/reporting/server/lib/deprecations/types.ts +++ b/x-pack/plugins/reporting/server/lib/deprecations/types.ts @@ -6,9 +6,7 @@ */ import type { ElasticsearchClient } from '@kbn/core/server'; -import type { ReportingCore } from '../../core'; export interface DeprecationsDependencies { - reportingCore: ReportingCore; elasticsearchClient: ElasticsearchClient; } diff --git a/x-pack/plugins/reporting/server/lib/store/ilm_policy_manager/ilm_policy_manager.ts b/x-pack/plugins/reporting/server/lib/store/ilm_policy_manager/ilm_policy_manager.ts index 90bda652898f3..950d6ea5e84c6 100644 --- a/x-pack/plugins/reporting/server/lib/store/ilm_policy_manager/ilm_policy_manager.ts +++ b/x-pack/plugins/reporting/server/lib/store/ilm_policy_manager/ilm_policy_manager.ts @@ -5,12 +5,19 @@ * 2.0. */ +import type { estypes } from '@elastic/elasticsearch'; import type { ElasticsearchClient } from '@kbn/core/server'; import { ILM_POLICY_NAME } from '@kbn/reporting-common'; -import { reportingIlmPolicy } from './constants'; +import { IlmPolicyMigrationStatus } from '@kbn/reporting-common/types'; +import { + REPORTING_DATA_STREAM_ALIAS, + REPORTING_DATA_STREAM_COMPONENT_TEMPLATE, + REPORTING_DATA_STREAM_WILDCARD, + REPORTING_LEGACY_INDICES, +} from '@kbn/reporting-server'; /** - * Responsible for detecting and provisioning the reporting ILM policy. + * Responsible for detecting and provisioning the reporting ILM policy in stateful deployments. * * Uses the provided {@link ElasticsearchClient} to scope request privileges. */ @@ -21,6 +28,9 @@ export class IlmPolicyManager { return new IlmPolicyManager(opts.client); } + /** + * Check that the ILM policy exists + */ public async doesIlmPolicyExist(): Promise { try { await this.client.ilm.getLifecycle({ name: ILM_POLICY_NAME }); @@ -33,13 +43,95 @@ export class IlmPolicyManager { } } + /** + * This method is automatically called on the Stack Management > Reporting page, by the `` API for users with + * privilege to manage ILM, to notify them when attention is needed to update the policy for any reason. + */ + public async checkIlmMigrationStatus(): Promise { + if (!(await this.doesIlmPolicyExist())) { + return 'policy-not-found'; + } + + const [reportingDataStreamSettings, reportingLegacyIndexSettings] = await Promise.all([ + this.client.indices.getSettings({ + index: REPORTING_DATA_STREAM_WILDCARD, + }), + this.client.indices.getSettings({ + index: REPORTING_LEGACY_INDICES, + }), + ]); + + const hasUnmanaged = (settings: estypes.IndicesIndexState) => { + return ( + settings?.settings?.index?.lifecycle?.name !== ILM_POLICY_NAME && + settings?.settings?.['index.lifecycle']?.name !== ILM_POLICY_NAME + ); + }; + + const hasUnmanagedDataStream = Object.values(reportingDataStreamSettings).some(hasUnmanaged); + const hasUnmanagedIndices = Object.values(reportingLegacyIndexSettings).some(hasUnmanaged); + + return hasUnmanagedDataStream || hasUnmanagedIndices ? 'indices-not-managed-by-policy' : 'ok'; + } + /** * Create the Reporting ILM policy */ public async createIlmPolicy(): Promise { await this.client.ilm.putLifecycle({ name: ILM_POLICY_NAME, - body: reportingIlmPolicy, + policy: { phases: { hot: { actions: {} } } }, + }); + } + + /** + * Update the Data Stream index template with a link to the Reporting ILM policy + */ + public async linkIlmPolicy() { + const putTemplateAcknowledged = await this.client.cluster.putComponentTemplate({ + name: REPORTING_DATA_STREAM_COMPONENT_TEMPLATE, + template: { settings: { lifecycle: { name: ILM_POLICY_NAME } } }, + create: false, + }); + + let backingIndicesAcknowledged: { acknowledged: boolean | null } = { acknowledged: null }; + const backingIndicesExist = await this.client.indices.exists({ + index: REPORTING_DATA_STREAM_ALIAS, + expand_wildcards: ['hidden'], + }); + if (backingIndicesExist) { + backingIndicesAcknowledged = await this.client.indices.putSettings({ + index: REPORTING_DATA_STREAM_ALIAS, + settings: { lifecycle: { name: ILM_POLICY_NAME } }, + }); + } + + return { putTemplateResponse: putTemplateAcknowledged, backingIndicesAcknowledged }; + } + + /** + * Update datastream to use ILM policy. If legacy indices exist, this attempts to link + * the ILM policy to them as well. + */ + public async migrateIndicesToIlmPolicy() { + const { + putTemplateResponse: { acknowledged: putTemplateAcknowledged }, + backingIndicesAcknowledged: { acknowledged: backingIndicesAcknowledged }, + } = await this.linkIlmPolicy(); + + let legacyAcknowledged: boolean | null = null; + const legacyExists = await this.client.indices.exists({ + index: REPORTING_LEGACY_INDICES, + expand_wildcards: ['hidden'], }); + if (legacyExists) { + const { acknowledged } = await this.client.indices.putSettings({ + index: REPORTING_LEGACY_INDICES, + settings: { lifecycle: { name: ILM_POLICY_NAME } }, + }); + legacyAcknowledged = acknowledged; + } + + return { putTemplateAcknowledged, backingIndicesAcknowledged, legacyAcknowledged }; } } diff --git a/x-pack/plugins/reporting/server/lib/store/ilm_policy_manager/index.ts b/x-pack/plugins/reporting/server/lib/store/ilm_policy_manager/index.ts index 045a9ecb59997..a10b1dbb26151 100644 --- a/x-pack/plugins/reporting/server/lib/store/ilm_policy_manager/index.ts +++ b/x-pack/plugins/reporting/server/lib/store/ilm_policy_manager/index.ts @@ -5,5 +5,4 @@ * 2.0. */ -export { reportingIlmPolicy } from './constants'; export { IlmPolicyManager } from './ilm_policy_manager'; diff --git a/x-pack/plugins/reporting/server/lib/store/mapping.ts b/x-pack/plugins/reporting/server/lib/store/mapping.ts deleted file mode 100644 index 9accfd0c75184..0000000000000 --- a/x-pack/plugins/reporting/server/lib/store/mapping.ts +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export const mapping = { - meta: { - // We are indexing these properties with both text and keyword fields - // because that's what will be auto generated when an index already exists. - properties: { - // ID of the app this report: search, visualization or dashboard, etc - objectType: { - type: 'text', - fields: { - keyword: { - type: 'keyword', - ignore_above: 256, - }, - }, - }, - layout: { - type: 'text', - fields: { - keyword: { - type: 'keyword', - ignore_above: 256, - }, - }, - }, - isDeprecated: { - type: 'boolean', - }, - }, - }, - migration_version: { type: 'keyword' }, // new field (7.14) to distinguish reports that were scheduled with Task Manager - jobtype: { type: 'keyword' }, - payload: { type: 'object', enabled: false }, - priority: { type: 'byte' }, // TODO: remove: this is unused - timeout: { type: 'long' }, - process_expiration: { type: 'date' }, - created_by: { type: 'keyword' }, // `null` if security is disabled - created_at: { type: 'date' }, - started_at: { type: 'date' }, - completed_at: { type: 'date' }, - attempts: { type: 'short' }, - max_attempts: { type: 'short' }, - kibana_name: { type: 'keyword' }, - kibana_id: { type: 'keyword' }, - status: { type: 'keyword' }, - parent_id: { type: 'keyword' }, - output: { - type: 'object', - properties: { - error_code: { type: 'keyword' }, - chunk: { type: 'long' }, - content_type: { type: 'keyword' }, - size: { type: 'long' }, - content: { type: 'object', enabled: false }, - }, - }, - metrics: { - type: 'object', - properties: { - csv: { - type: 'object', - properties: { - rows: { type: 'long' }, - }, - }, - pdf: { - type: 'object', - properties: { - pages: { type: 'long' }, - cpu: { type: 'double' }, - cpuInPercentage: { type: 'double' }, - memory: { type: 'long' }, - memoryInMegabytes: { type: 'double' }, - }, - }, - png: { - type: 'object', - properties: { - cpu: { type: 'double' }, - cpuInPercentage: { type: 'double' }, - memory: { type: 'long' }, - memoryInMegabytes: { type: 'double' }, - }, - }, - }, - }, -} as const; diff --git a/x-pack/plugins/reporting/server/lib/store/report.test.ts b/x-pack/plugins/reporting/server/lib/store/report.test.ts index f6cbbade4df7b..ca1294f663da8 100644 --- a/x-pack/plugins/reporting/server/lib/store/report.test.ts +++ b/x-pack/plugins/reporting/server/lib/store/report.test.ts @@ -124,6 +124,9 @@ describe('Class Report', () => { it('throws error if converted to task JSON before being synced with ES storage', () => { const report = new Report({ jobtype: 'spam', payload: {} } as any); + // @ts-ignore null is not applicable to string + report._index = null; + expect(() => report.updateWithEsDoc(report)).toThrowErrorMatchingInlineSnapshot( `"Report object from ES has missing fields!"` ); diff --git a/x-pack/plugins/reporting/server/lib/store/report.ts b/x-pack/plugins/reporting/server/lib/store/report.ts index e62f4f2f20b58..6eb0960aedd93 100644 --- a/x-pack/plugins/reporting/server/lib/store/report.ts +++ b/x-pack/plugins/reporting/server/lib/store/report.ts @@ -10,6 +10,7 @@ import moment from 'moment'; import { v4 as uuidv4 } from 'uuid'; import { JOB_STATUS } from '@kbn/reporting-common'; +import { REPORTING_DATA_STREAM_ALIAS } from '@kbn/reporting-server'; import { ReportApiJSON, ReportDocumentHead, @@ -25,7 +26,7 @@ export const MIGRATION_VERSION = '7.14.0'; * Class for an ephemeral report document: possibly is not saved in Elasticsearch */ export class Report implements Partial { - public _index?: string; + public _index: string; public _id: string; public _primary_term?: number; // set by ES public _seq_no?: number; // set by ES @@ -63,7 +64,7 @@ export class Report implements Partial { */ constructor(opts: Partial & Partial, fields?: ReportFields) { this._id = opts._id != null ? opts._id : uuidv4(); - this._index = opts._index; + this._index = opts._index ?? REPORTING_DATA_STREAM_ALIAS; // Sets the value to the data stream, unless it's a stored report and we know the name of the backing index this._primary_term = opts._primary_term; this._seq_no = opts._seq_no; @@ -167,7 +168,7 @@ export class Report implements Partial { toApiJSON(): ReportApiJSON { return { id: this._id, - index: this._index!, + index: this._index ?? REPORTING_DATA_STREAM_ALIAS, kibana_name: this.kibana_name, kibana_id: this.kibana_id, jobtype: this.jobtype, diff --git a/x-pack/plugins/reporting/server/lib/store/store.test.ts b/x-pack/plugins/reporting/server/lib/store/store.test.ts index 946ceb4f105b0..826e13c0ac696 100644 --- a/x-pack/plugins/reporting/server/lib/store/store.test.ts +++ b/x-pack/plugins/reporting/server/lib/store/store.test.ts @@ -80,70 +80,6 @@ describe('ReportingStore', () => { ); }); - it('handles error creating the index', async () => { - // setup - mockEsClient.indices.exists.mockResponse(false); - mockEsClient.indices.create.mockRejectedValue(new Error('horrible error')); - - const store = new ReportingStore(mockCore, mockLogger); - const mockReport = new Report({ - _index: '.reporting-errortest', - jobtype: 'unknowntype', - payload: {}, - meta: {}, - } as any); - await expect(store.addReport(mockReport)).rejects.toMatchInlineSnapshot( - `[Error: horrible error]` - ); - }); - - /* Creating the index will fail, if there were multiple jobs staged in - * parallel and creation completed from another Kibana instance. Only the - * first request in line can successfully create it. - * In spite of that race condition, adding the new job in Elasticsearch is - * fine. - */ - it('ignores index creation error if the index already exists and continues adding the report', async () => { - // setup - mockEsClient.indices.exists.mockResponse(false); - mockEsClient.indices.create.mockRejectedValue(new Error('devastating error')); - - const store = new ReportingStore(mockCore, mockLogger); - const mockReport = new Report({ - _index: '.reporting-mock', - jobtype: 'unknowntype', - payload: {}, - meta: {}, - } as any); - await expect(store.addReport(mockReport)).rejects.toMatchInlineSnapshot( - `[Error: devastating error]` - ); - }); - - it('skips creating the index if already exists', async () => { - // setup - mockEsClient.indices.exists.mockResponse(false); - // will be triggered but ignored - mockEsClient.indices.create.mockRejectedValue(new Error('resource_already_exists_exception')); - - const store = new ReportingStore(mockCore, mockLogger); - const mockReport = new Report({ - created_by: 'user1', - jobtype: 'unknowntype', - payload: {}, - meta: {}, - } as any); - await expect(store.addReport(mockReport)).resolves.toMatchObject({ - _primary_term: undefined, - _seq_no: undefined, - attempts: 0, - created_by: 'user1', - jobtype: 'unknowntype', - payload: {}, - status: 'pending', - }); - }); - it('allows username string to be `false`', async () => { // setup mockEsClient.indices.exists.mockResponse(false); @@ -426,16 +362,14 @@ describe('ReportingStore', () => { expect(mockEsClient.ilm.getLifecycle).toHaveBeenCalledWith({ name: 'kibana-reporting' }); expect(mockEsClient.ilm.putLifecycle.mock.calls[0][0]).toMatchInlineSnapshot(` Object { - "body": Object { - "policy": Object { - "phases": Object { - "hot": Object { - "actions": Object {}, - }, + "name": "kibana-reporting", + "policy": Object { + "phases": Object { + "hot": Object { + "actions": Object {}, }, }, }, - "name": "kibana-reporting", } `); }); diff --git a/x-pack/plugins/reporting/server/lib/store/store.ts b/x-pack/plugins/reporting/server/lib/store/store.ts index 543045393a1b2..648230113780d 100644 --- a/x-pack/plugins/reporting/server/lib/store/store.ts +++ b/x-pack/plugins/reporting/server/lib/store/store.ts @@ -14,15 +14,16 @@ import type { ReportOutput, ReportSource, } from '@kbn/reporting-common/types'; -import { REPORTING_SYSTEM_INDEX } from '@kbn/reporting-server'; +import { + REPORTING_DATA_STREAM_ALIAS, + REPORTING_DATA_STREAM_COMPONENT_TEMPLATE, +} from '@kbn/reporting-server'; import moment from 'moment'; import type { Report } from '.'; import { SavedReport } from '.'; import type { ReportingCore } from '../..'; import type { ReportTaskParams } from '../tasks'; import { IlmPolicyManager } from './ilm_policy_manager'; -import { indexTimestamp } from './index_timestamp'; -import { mapping } from './mapping'; import { MIGRATION_VERSION } from './report'; type UpdateResponse = estypes.UpdateResponse; @@ -71,6 +72,7 @@ const sourceDoc = (doc: Partial): Partial => { return { ...doc, migration_version: MIGRATION_VERSION, + '@timestamp': new Date(0).toISOString(), // required for data streams compatibility }; }; @@ -103,16 +105,9 @@ const jobDebugMessage = (report: Report) => * - interface for downloading the report */ export class ReportingStore { - private readonly indexPrefix: string; // config setting of index prefix in system index name - private readonly indexInterval: string; // config setting of index prefix: how often to poll for pending work private client?: ElasticsearchClient; - config: ReportingCore['config']; constructor(private reportingCore: ReportingCore, private logger: Logger) { - this.config = reportingCore.getConfig(); - - this.indexPrefix = REPORTING_SYSTEM_INDEX; - this.indexInterval = this.config.queue.indexInterval; this.logger = logger.get('store'); } @@ -124,62 +119,28 @@ export class ReportingStore { return this.client; } - private async getIlmPolicyManager() { - const client = await this.getClient(); - return IlmPolicyManager.create({ client }); - } - - private async createIndex(indexName: string) { + private async createIlmPolicy() { const client = await this.getClient(); - const exists = await client.indices.exists({ index: indexName }); - - if (exists) { - return exists; + const ilmPolicyManager = IlmPolicyManager.create({ client }); + if (await ilmPolicyManager.doesIlmPolicyExist()) { + this.logger.debug(`Found ILM policy ${ILM_POLICY_NAME}; skipping creation.`); + } else { + this.logger.info(`Creating ILM policy for reporting data stream: ${ILM_POLICY_NAME}`); + await ilmPolicyManager.createIlmPolicy(); } - const indexSettings = this.config.statefulSettings.enabled - ? { - settings: { - number_of_shards: 1, - auto_expand_replicas: '0-1', - lifecycle: { - name: ILM_POLICY_NAME, - }, - }, - } - : {}; - - try { - await client.indices.create({ - index: indexName, - body: { - ...indexSettings, - mappings: { - properties: mapping, - }, - }, - }); - - return true; - } catch (error) { - const isIndexExistsError = error.message.match(/resource_already_exists_exception/); - if (isIndexExistsError) { - // Do not fail a job if the job runner hits the race condition. - this.logger.warn(`Automatic index creation failed: index already exists: ${error}`); - return; - } - - this.logger.error(error); - - throw error; - } + this.logger.info( + `Linking ILM policy to reporting data stream: ${REPORTING_DATA_STREAM_ALIAS}, component template: ${REPORTING_DATA_STREAM_COMPONENT_TEMPLATE}` + ); + await ilmPolicyManager.linkIlmPolicy(); } private async indexReport(report: Report): Promise { const doc = { - index: report._index!, + index: REPORTING_DATA_STREAM_ALIAS, id: report._id, refresh: 'wait_for' as estypes.Refresh, + op_type: 'create' as const, body: { ...report.toReportSource(), ...sourceDoc({ @@ -193,52 +154,23 @@ export class ReportingStore { return await client.index(doc); } - /* - * Called from addReport, which handles any errors - */ - private async refreshIndex(index: string) { - const client = await this.getClient(); - - return client.indices.refresh({ index }); - } - /** * Function to be called during plugin start phase. This ensures the environment is correctly * configured for storage of reports. */ public async start() { - if (!this.config.statefulSettings.enabled) { - return; - } - const ilmPolicyManager = await this.getIlmPolicyManager(); try { - if (await ilmPolicyManager.doesIlmPolicyExist()) { - this.logger.debug(`Found ILM policy ${ILM_POLICY_NAME}; skipping creation.`); - return; - } - this.logger.info(`Creating ILM policy for managing reporting indices: ${ILM_POLICY_NAME}`); - await ilmPolicyManager.createIlmPolicy(); + await this.createIlmPolicy(); } catch (e) { this.logger.error('Error in start phase'); - this.logger.error(e.body?.error); + this.logger.error(e); throw e; } } public async addReport(report: Report): Promise { - let index = report._index; - if (!index) { - const timestamp = indexTimestamp(this.indexInterval); - index = `${this.indexPrefix}-${timestamp}`; - report._index = index; - } - await this.createIndex(index); - try { report.updateWithEsDoc(await this.indexReport(report)); - - await this.refreshIndex(index); - return report as SavedReport; } catch (err) { this.reportingCore.getEventLogger(report).logError(err); @@ -402,8 +334,4 @@ export class ReportingStore { return body; } - - public getReportingIndexPattern(): string { - return `${this.indexPrefix}-*`; - } } diff --git a/x-pack/plugins/reporting/server/routes/common/jobs/get_document_payload.ts b/x-pack/plugins/reporting/server/routes/common/jobs/get_document_payload.ts index d8a0027c42d64..c77e04ec66c22 100644 --- a/x-pack/plugins/reporting/server/routes/common/jobs/get_document_payload.ts +++ b/x-pack/plugins/reporting/server/routes/common/jobs/get_document_payload.ts @@ -54,6 +54,8 @@ const getReportingHeaders = (output: TaskRunResult, exportType: ExportType) => { }; export function getDocumentPayloadFactory(reporting: ReportingCore) { + const { logger: _logger } = reporting.getPluginSetupDeps(); + const logger = _logger.get('download-report'); const exportTypesRegistry = reporting.getExportTypesRegistry(); async function getCompleted({ @@ -88,6 +90,8 @@ export function getDocumentPayloadFactory(reporting: ReportingCore) { const jobsQuery = jobsQueryFactory(reporting); const error = await jobsQuery.getError(id); + logger.debug(`Report job ${id} has failed. Sending statusCode: 500`); + return { statusCode: 500, content: { @@ -98,7 +102,9 @@ export function getDocumentPayloadFactory(reporting: ReportingCore) { }; } - function getIncomplete({ status }: ReportApiJSON): Payload { + function getIncomplete({ id, status }: ReportApiJSON): Payload { + logger.debug(`Report job ${id} is processing. Sending statusCode: 503`); + return { statusCode: 503, content: status, diff --git a/x-pack/plugins/reporting/server/routes/common/jobs/jobs_query.ts b/x-pack/plugins/reporting/server/routes/common/jobs/jobs_query.ts index d371d49970a72..56b0ac4677449 100644 --- a/x-pack/plugins/reporting/server/routes/common/jobs/jobs_query.ts +++ b/x-pack/plugins/reporting/server/routes/common/jobs/jobs_query.ts @@ -10,7 +10,7 @@ import type { ElasticsearchClient } from '@kbn/core/server'; import { i18n } from '@kbn/i18n'; import { JOB_STATUS } from '@kbn/reporting-common'; import type { ReportApiJSON, ReportSource } from '@kbn/reporting-common/types'; -import { REPORTING_SYSTEM_INDEX } from '@kbn/reporting-server'; +import { REPORTING_DATA_STREAM_WILDCARD_WITH_LEGACY } from '@kbn/reporting-server'; import type { ReportingCore } from '../../..'; import { Report } from '../../../lib/store'; import { runtimeFieldKeys, runtimeFields } from '../../../lib/store/runtime_fields'; @@ -54,10 +54,6 @@ export interface JobsQueryFactory { } export function jobsQueryFactory(reportingCore: ReportingCore): JobsQueryFactory { - function getIndex() { - return `${REPORTING_SYSTEM_INDEX}-*`; - } - async function execQuery< T extends (client: ElasticsearchClient) => Promise> | undefined> >(callback: T): Promise> | undefined> { @@ -96,7 +92,7 @@ export function jobsQueryFactory(reportingCore: ReportingCore): JobsQueryFactory }); const response = (await execQuery((elasticsearchClient) => - elasticsearchClient.search({ body, index: getIndex() }) + elasticsearchClient.search({ body, index: REPORTING_DATA_STREAM_WILDCARD_WITH_LEGACY }) )) as estypes.SearchResponse; return ( @@ -127,7 +123,7 @@ export function jobsQueryFactory(reportingCore: ReportingCore): JobsQueryFactory }; const response = await execQuery((elasticsearchClient) => - elasticsearchClient.count({ body, index: getIndex() }) + elasticsearchClient.count({ body, index: REPORTING_DATA_STREAM_WILDCARD_WITH_LEGACY }) ); return response?.count ?? 0; @@ -156,7 +152,10 @@ export function jobsQueryFactory(reportingCore: ReportingCore): JobsQueryFactory }); const response = await execQuery((elasticsearchClient) => - elasticsearchClient.search({ body, index: getIndex() }) + elasticsearchClient.search({ + body, + index: REPORTING_DATA_STREAM_WILDCARD_WITH_LEGACY, + }) ); const result = response?.hits?.hits?.[0]; @@ -187,7 +186,10 @@ export function jobsQueryFactory(reportingCore: ReportingCore): JobsQueryFactory }; const response = await execQuery((elasticsearchClient) => - elasticsearchClient.search({ body, index: getIndex() }) + elasticsearchClient.search({ + body, + index: REPORTING_DATA_STREAM_WILDCARD_WITH_LEGACY, + }) ); const hits = response?.hits?.hits?.[0]; const status = hits?._source?.status; diff --git a/x-pack/plugins/reporting/server/routes/internal/deprecations/deprecations.ts b/x-pack/plugins/reporting/server/routes/internal/deprecations/deprecations.ts index d35adf717cbb9..ae8ff7fd55cf1 100644 --- a/x-pack/plugins/reporting/server/routes/internal/deprecations/deprecations.ts +++ b/x-pack/plugins/reporting/server/routes/internal/deprecations/deprecations.ts @@ -6,11 +6,11 @@ */ import { errors } from '@elastic/elasticsearch'; import type { Logger, RequestHandler } from '@kbn/core/server'; -import { ILM_POLICY_NAME, INTERNAL_ROUTES } from '@kbn/reporting-common'; -import type { IlmPolicyStatusResponse } from '@kbn/reporting-common/url'; +import { INTERNAL_ROUTES } from '@kbn/reporting-common'; +import type { IlmPolicyStatusResponse } from '@kbn/reporting-common/types'; +import { REPORTING_DATA_STREAM_WILDCARD_WITH_LEGACY } from '@kbn/reporting-server'; import type { ReportingCore } from '../../../core'; import { IlmPolicyManager } from '../../../lib'; -import { deprecations } from '../../../lib/deprecations'; import { getCounters } from '../../common'; const getAuthzWrapper = @@ -24,15 +24,13 @@ const getAuthzWrapper = const { elasticsearch } = await ctx.core; - const store = await reporting.getStore(); - try { const body = await elasticsearch.client.asCurrentUser.security.hasPrivileges({ body: { index: [ { privileges: ['manage'], // required to do anything with the reporting indices - names: [store.getReportingIndexPattern()], + names: [REPORTING_DATA_STREAM_WILDCARD_WITH_LEGACY], allow_restricted_indices: true, }, ], @@ -65,15 +63,11 @@ export const registerDeprecationsRoutes = (reporting: ReportingCore, logger: Log authzWrapper(async ({ core }, req, res) => { const counters = getCounters(req.route.method, getStatusPath, reporting.getUsageCounter()); - const { - elasticsearch: { client: scopedClient }, - } = await core; - const checkIlmMigrationStatus = () => { - return deprecations.checkIlmMigrationStatus({ - reportingCore: reporting, - // We want to make the current status visible to all reporting users - elasticsearchClient: scopedClient.asInternalUser, - }); + const checkIlmMigrationStatus = async () => { + const { client: scopedClient } = (await core).elasticsearch; + + const ilmPolicyManager = IlmPolicyManager.create({ client: scopedClient.asInternalUser }); + return ilmPolicyManager.checkIlmMigrationStatus(); }; try { @@ -106,17 +100,15 @@ export const registerDeprecationsRoutes = (reporting: ReportingCore, logger: Log authzWrapper(async ({ core }, req, res) => { const counters = getCounters(req.route.method, migrateApiPath, reporting.getUsageCounter()); - const store = await reporting.getStore(); - const { - client: { asCurrentUser: client }, - } = (await core).elasticsearch; - - const scopedIlmPolicyManager = IlmPolicyManager.create({ - client, - }); - // First we ensure that the reporting ILM policy exists in the cluster try { + const { + client: { asCurrentUser }, + } = (await core).elasticsearch; + const scopedIlmPolicyManager = IlmPolicyManager.create({ + client: asCurrentUser, + }); + // We don't want to overwrite an existing reporting policy because it may contain alterations made by users if (!(await scopedIlmPolicyManager.doesIlmPolicyExist())) { await scopedIlmPolicyManager.createIlmPolicy(); @@ -125,24 +117,19 @@ export const registerDeprecationsRoutes = (reporting: ReportingCore, logger: Log return res.customError({ statusCode: e?.statusCode ?? 500, body: { message: e.message } }); } - const indexPattern = store.getReportingIndexPattern(); - // Second we migrate all of the existing indices to be managed by the reporting ILM policy try { - await client.indices.putSettings({ - index: indexPattern, - body: { - index: { - lifecycle: { - name: ILM_POLICY_NAME, - }, - }, - }, + const { + client: { asInternalUser }, + } = (await core).elasticsearch; + const unscopedIlmPolicyManager = IlmPolicyManager.create({ + client: asInternalUser, }); + const response = await unscopedIlmPolicyManager.migrateIndicesToIlmPolicy(); counters.usageCounter(); - return res.ok(); + return res.ok({ body: response }); } catch (err) { logger.error(err); diff --git a/x-pack/plugins/rule_registry/server/utils/get_alerts_for_notification.test.ts b/x-pack/plugins/rule_registry/server/utils/get_alerts_for_notification.test.ts index a6f428d598262..f6ce39f34d0a1 100644 --- a/x-pack/plugins/rule_registry/server/utils/get_alerts_for_notification.test.ts +++ b/x-pack/plugins/rule_registry/server/utils/get_alerts_for_notification.test.ts @@ -245,6 +245,13 @@ describe('getAlertsForNotification', () => { ).toMatchInlineSnapshot(`Array []`); }); + test('should not return recovered alerts if the activeCount is less than the rule alertDelay', () => { + const trackedEvents = cloneDeep([alert1]); + expect( + getAlertsForNotification(DEFAULT_FLAPPING_SETTINGS, 5, trackedEvents, [], newEventParams) + ).toMatchInlineSnapshot(`Array []`); + }); + test('should update active alert to look like a new alert if the activeCount is equal to the rule alertDelay', () => { const trackedEvents = cloneDeep([alert5]); expect( diff --git a/x-pack/plugins/rule_registry/server/utils/get_alerts_for_notification.ts b/x-pack/plugins/rule_registry/server/utils/get_alerts_for_notification.ts index 15dcedeaf88ca..73cbac1b2c90a 100644 --- a/x-pack/plugins/rule_registry/server/utils/get_alerts_for_notification.ts +++ b/x-pack/plugins/rule_registry/server/utils/get_alerts_for_notification.ts @@ -56,6 +56,10 @@ export function getAlertsForNotification( } } } else if (trackedEvent.event[ALERT_STATUS] === ALERT_STATUS_RECOVERED) { + // if alert has not reached the alertDelay threshold don't recover the alert + if (trackedEvent.activeCount < alertDelay) { + continue; + } trackedEvent.activeCount = 0; if (flappingSettings.enabled) { if (trackedEvent.flapping) { diff --git a/x-pack/plugins/search_connectors/common/connectors.ts b/x-pack/plugins/search_connectors/common/connectors.ts index dd96c11487279..647e1b3b6d266 100644 --- a/x-pack/plugins/search_connectors/common/connectors.ts +++ b/x-pack/plugins/search_connectors/common/connectors.ts @@ -708,7 +708,7 @@ export const CONNECTOR_DEFINITIONS: ConnectorServerSideDefinition[] = [ } ), iconPath: 'custom.svg', - isBeta: true, + isBeta: false, isNative: false, keywords: ['custom', 'connector', 'code'], name: i18n.translate('searchConnectorsPlugin.content.nativeConnectors.customConnector.name', { diff --git a/x-pack/plugins/search_notebooks/server/data/00_quick_start.json b/x-pack/plugins/search_notebooks/server/data/00_quick_start.json index bb5ee71326683..53b3ca4e55587 100644 --- a/x-pack/plugins/search_notebooks/server/data/00_quick_start.json +++ b/x-pack/plugins/search_notebooks/server/data/00_quick_start.json @@ -70,7 +70,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "WHC3hHGW-wbI", "metadata": { "id": "WHC3hHGW-wbI" @@ -96,7 +96,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "f38e0397", "metadata": { "colab": { @@ -137,17 +137,39 @@ }, { "cell_type": "markdown", - "id": "1462ebd8", - "metadata": { - "id": "1462ebd8" - }, + "id": "cb6ad7e9-0636-4cf3-a803-bf160fe16b33", + "metadata": {}, "source": [ - "Confirm that the client has connected with this test." + "### Enable Telemetry\n", + "\n", + "Knowing that you are using this notebook helps us decide where to invest our efforts to improve our products. We would like to ask you that you run the following code to let us gather anonymous usage statistics. See [telemetry.py](https://github.com/elastic/elasticsearch-labs/blob/main/telemetry/telemetry.py) for details. Thank you!" ] }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, + "id": "3b04f442-729d-406d-b826-654483498df6", + "metadata": {}, + "outputs": [], + "source": [ + "!curl -O -s https://raw.githubusercontent.com/elastic/elasticsearch-labs/main/telemetry/telemetry.py\n", + "from telemetry import enable_telemetry\n", + "\n", + "client = enable_telemetry(client, \"00-quick-start\")" + ] + }, + { + "cell_type": "markdown", + "id": "d12b707c-e89d-4b43-bee5-edb1beb84839", + "metadata": {}, + "source": [ + "### Test the Client\n", + "Before you continue, confirm that the client has connected with this test." + ] + }, + { + "cell_type": "code", + "execution_count": 8, "id": "25c618eb", "metadata": { "colab": { @@ -161,7 +183,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "{'name': 'instance-0000000011', 'cluster_name': 'd1bd36862ce54c7b903e2aacd4cd7f0a', 'cluster_uuid': 'tIkh0X_UQKmMFQKSfUw-VQ', 'version': {'number': '8.9.0', 'build_flavor': 'default', 'build_type': 'docker', 'build_hash': '8aa461beb06aa0417a231c345a1b8c38fb498a0d', 'build_date': '2023-07-19T14:43:58.555259655Z', 'build_snapshot': False, 'lucene_version': '9.7.0', 'minimum_wire_compatibility_version': '7.17.0', 'minimum_index_compatibility_version': '7.0.0'}, 'tagline': 'You Know, for Search'}\n" + "{'name': 'instance-0000000000', 'cluster_name': 'a72482be54904952ba46d53c3def7740', 'cluster_uuid': 'g8BE52TtT32pGBbRzP_oKA', 'version': {'number': '8.12.2', 'build_flavor': 'default', 'build_type': 'docker', 'build_hash': '48a287ab9497e852de30327444b0809e55d46466', 'build_date': '2024-02-19T10:04:32.774273190Z', 'build_snapshot': False, 'lucene_version': '9.9.2', 'minimum_wire_compatibility_version': '7.17.0', 'minimum_index_compatibility_version': '7.0.0'}, 'tagline': 'You Know, for Search'}\n" ] } ], @@ -195,7 +217,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 9, "id": "_OAahfg-tqrf", "metadata": { "colab": { @@ -211,7 +233,7 @@ "ObjectApiResponse({'acknowledged': True})" ] }, - "execution_count": 5, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -232,7 +254,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 10, "id": "6bc95238", "metadata": { "id": "6bc95238" @@ -244,7 +266,7 @@ "ObjectApiResponse({'acknowledged': True, 'shards_acknowledged': True, 'index': 'book_index'})" ] }, - "execution_count": 11, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -281,7 +303,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 13, "id": "008d723e", "metadata": { "id": "008d723e" @@ -290,10 +312,10 @@ { "data": { "text/plain": [ - "ObjectApiResponse({'took': 49, 'errors': False, 'items': [{'index': {'_index': 'book_index', '_id': 'HwOa7osBiUNHLMdf3q2r', '_version': 1, 'result': 'created', 'forced_refresh': True, '_shards': {'total': 2, 'successful': 1, 'failed': 0}, '_seq_no': 0, '_primary_term': 1, 'status': 201}}, {'index': {'_index': 'book_index', '_id': 'IAOa7osBiUNHLMdf3q2r', '_version': 1, 'result': 'created', 'forced_refresh': True, '_shards': {'total': 2, 'successful': 1, 'failed': 0}, '_seq_no': 1, '_primary_term': 1, 'status': 201}}, {'index': {'_index': 'book_index', '_id': 'IQOa7osBiUNHLMdf3q2r', '_version': 1, 'result': 'created', 'forced_refresh': True, '_shards': {'total': 2, 'successful': 1, 'failed': 0}, '_seq_no': 2, '_primary_term': 1, 'status': 201}}, {'index': {'_index': 'book_index', '_id': 'IgOa7osBiUNHLMdf3q2r', '_version': 1, 'result': 'created', 'forced_refresh': True, '_shards': {'total': 2, 'successful': 1, 'failed': 0}, '_seq_no': 3, '_primary_term': 1, 'status': 201}}, {'index': {'_index': 'book_index', '_id': 'IwOa7osBiUNHLMdf3q2r', '_version': 1, 'result': 'created', 'forced_refresh': True, '_shards': {'total': 2, 'successful': 1, 'failed': 0}, '_seq_no': 4, '_primary_term': 1, 'status': 201}}, {'index': {'_index': 'book_index', '_id': 'JAOa7osBiUNHLMdf3q2r', '_version': 1, 'result': 'created', 'forced_refresh': True, '_shards': {'total': 2, 'successful': 1, 'failed': 0}, '_seq_no': 5, '_primary_term': 1, 'status': 201}}, {'index': {'_index': 'book_index', '_id': 'JQOa7osBiUNHLMdf3q2r', '_version': 1, 'result': 'created', 'forced_refresh': True, '_shards': {'total': 2, 'successful': 1, 'failed': 0}, '_seq_no': 6, '_primary_term': 1, 'status': 201}}, {'index': {'_index': 'book_index', '_id': 'JgOa7osBiUNHLMdf3q2r', '_version': 1, 'result': 'created', 'forced_refresh': True, '_shards': {'total': 2, 'successful': 1, 'failed': 0}, '_seq_no': 7, '_primary_term': 1, 'status': 201}}, {'index': {'_index': 'book_index', '_id': 'JwOa7osBiUNHLMdf3q2r', '_version': 1, 'result': 'created', 'forced_refresh': True, '_shards': {'total': 2, 'successful': 1, 'failed': 0}, '_seq_no': 8, '_primary_term': 1, 'status': 201}}, {'index': {'_index': 'book_index', '_id': 'KAOa7osBiUNHLMdf3q2r', '_version': 1, 'result': 'created', 'forced_refresh': True, '_shards': {'total': 2, 'successful': 1, 'failed': 0}, '_seq_no': 9, '_primary_term': 1, 'status': 201}}]})" + "ObjectApiResponse({'errors': False, 'took': 88, 'items': [{'index': {'_index': 'book_index', '_id': 'caRpvY4BKY8PuI1qPluy', '_version': 1, 'result': 'created', 'forced_refresh': True, '_shards': {'total': 2, 'successful': 2, 'failed': 0}, '_seq_no': 0, '_primary_term': 1, 'status': 201}}, {'index': {'_index': 'book_index', '_id': 'cqRpvY4BKY8PuI1qPluy', '_version': 1, 'result': 'created', 'forced_refresh': True, '_shards': {'total': 2, 'successful': 2, 'failed': 0}, '_seq_no': 1, '_primary_term': 1, 'status': 201}}, {'index': {'_index': 'book_index', '_id': 'c6RpvY4BKY8PuI1qPluy', '_version': 1, 'result': 'created', 'forced_refresh': True, '_shards': {'total': 2, 'successful': 2, 'failed': 0}, '_seq_no': 2, '_primary_term': 1, 'status': 201}}, {'index': {'_index': 'book_index', '_id': 'dKRpvY4BKY8PuI1qPluy', '_version': 1, 'result': 'created', 'forced_refresh': True, '_shards': {'total': 2, 'successful': 2, 'failed': 0}, '_seq_no': 3, '_primary_term': 1, 'status': 201}}, {'index': {'_index': 'book_index', '_id': 'daRpvY4BKY8PuI1qPluy', '_version': 1, 'result': 'created', 'forced_refresh': True, '_shards': {'total': 2, 'successful': 2, 'failed': 0}, '_seq_no': 4, '_primary_term': 1, 'status': 201}}, {'index': {'_index': 'book_index', '_id': 'dqRpvY4BKY8PuI1qPluy', '_version': 1, 'result': 'created', 'forced_refresh': True, '_shards': {'total': 2, 'successful': 2, 'failed': 0}, '_seq_no': 5, '_primary_term': 1, 'status': 201}}, {'index': {'_index': 'book_index', '_id': 'd6RpvY4BKY8PuI1qPluy', '_version': 1, 'result': 'created', 'forced_refresh': True, '_shards': {'total': 2, 'successful': 2, 'failed': 0}, '_seq_no': 6, '_primary_term': 1, 'status': 201}}, {'index': {'_index': 'book_index', '_id': 'eKRpvY4BKY8PuI1qPluy', '_version': 1, 'result': 'created', 'forced_refresh': True, '_shards': {'total': 2, 'successful': 2, 'failed': 0}, '_seq_no': 7, '_primary_term': 1, 'status': 201}}, {'index': {'_index': 'book_index', '_id': 'eaRpvY4BKY8PuI1qPluy', '_version': 1, 'result': 'created', 'forced_refresh': True, '_shards': {'total': 2, 'successful': 2, 'failed': 0}, '_seq_no': 8, '_primary_term': 1, 'status': 201}}, {'index': {'_index': 'book_index', '_id': 'eqRpvY4BKY8PuI1qPluy', '_version': 1, 'result': 'created', 'forced_refresh': True, '_shards': {'total': 2, 'successful': 2, 'failed': 0}, '_seq_no': 9, '_primary_term': 1, 'status': 201}}]})" ] }, - "execution_count": 12, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } @@ -330,7 +352,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 14, "id": "f12ce2c9", "metadata": { "id": "f12ce2c9" @@ -369,7 +391,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 15, "id": "Df7hwcIjYwMT", "metadata": { "colab": { @@ -384,16 +406,16 @@ "output_type": "stream", "text": [ "\n", - "ID: JwOa7osBiUNHLMdf3q2r\n", + "ID: eaRpvY4BKY8PuI1qPluy\n", "Publication date: 2008-05-15\n", "Title: JavaScript: The Good Parts\n", "Summary: A deep dive into the parts of JavaScript that are essential to writing maintainable code\n", "Publisher: oreilly\n", "Reviews: 51\n", "Authors: ['douglas crockford']\n", - "Score: 0.80428284\n", + "Score: 0.8042828\n", "\n", - "ID: IwOa7osBiUNHLMdf3q2r\n", + "ID: daRpvY4BKY8PuI1qPluy\n", "Publication date: 2015-03-27\n", "Title: You Don't Know JS: Up & Going\n", "Summary: Introduction to JavaScript and programming as a whole\n", @@ -402,7 +424,7 @@ "Authors: ['kyle simpson']\n", "Score: 0.6989136\n", "\n", - "ID: JAOa7osBiUNHLMdf3q2r\n", + "ID: dqRpvY4BKY8PuI1qPluy\n", "Publication date: 2018-12-04\n", "Title: Eloquent JavaScript\n", "Summary: A modern introduction to programming\n", @@ -411,25 +433,25 @@ "Authors: ['marijn haverbeke']\n", "Score: 0.6796988\n", "\n", - "ID: HwOa7osBiUNHLMdf3q2r\n", + "ID: caRpvY4BKY8PuI1qPluy\n", "Publication date: 2019-10-29\n", "Title: The Pragmatic Programmer: Your Journey to Mastery\n", "Summary: A guide to pragmatic programming for software engineers and developers\n", "Publisher: addison-wesley\n", "Reviews: 30\n", "Authors: ['andrew hunt', 'david thomas']\n", - "Score: 0.62065494\n", + "Score: 0.6206549\n", "\n", - "ID: KAOa7osBiUNHLMdf3q2r\n", + "ID: eqRpvY4BKY8PuI1qPluy\n", "Publication date: 2012-06-27\n", "Title: Introduction to the Theory of Computation\n", "Summary: Introduction to the theory of computation and complexity theory\n", "Publisher: cengage learning\n", "Reviews: 33\n", "Authors: ['michael sipser']\n", - "Score: 0.6008769\n", + "Score: 0.60087687\n", "\n", - "ID: JgOa7osBiUNHLMdf3q2r\n", + "ID: eKRpvY4BKY8PuI1qPluy\n", "Publication date: 2011-05-13\n", "Title: The Clean Coder: A Code of Conduct for Professional Programmers\n", "Summary: A guide to professional conduct in the field of software engineering\n", @@ -438,7 +460,7 @@ "Authors: ['robert c. martin']\n", "Score: 0.571234\n", "\n", - "ID: JQOa7osBiUNHLMdf3q2r\n", + "ID: d6RpvY4BKY8PuI1qPluy\n", "Publication date: 1994-10-31\n", "Title: Design Patterns: Elements of Reusable Object-Oriented Software\n", "Summary: Guide to design patterns that can be used in any object-oriented language\n", @@ -447,32 +469,32 @@ "Authors: ['erich gamma', 'richard helm', 'ralph johnson', 'john vlissides']\n", "Score: 0.56499225\n", "\n", - "ID: IQOa7osBiUNHLMdf3q2r\n", + "ID: c6RpvY4BKY8PuI1qPluy\n", "Publication date: 2020-04-06\n", "Title: Artificial Intelligence: A Modern Approach\n", "Summary: Comprehensive introduction to the theory and practice of artificial intelligence\n", "Publisher: pearson\n", "Reviews: 39\n", "Authors: ['stuart russell', 'peter norvig']\n", - "Score: 0.56054837\n", + "Score: 0.5605484\n", "\n", - "ID: IgOa7osBiUNHLMdf3q2r\n", + "ID: dKRpvY4BKY8PuI1qPluy\n", "Publication date: 2008-08-11\n", "Title: Clean Code: A Handbook of Agile Software Craftsmanship\n", "Summary: A guide to writing code that is easy to read, understand and maintain\n", "Publisher: prentice hall\n", "Reviews: 55\n", "Authors: ['robert c. martin']\n", - "Score: 0.54226947\n", + "Score: 0.5422694\n", "\n", - "ID: IAOa7osBiUNHLMdf3q2r\n", + "ID: cqRpvY4BKY8PuI1qPluy\n", "Publication date: 2019-05-03\n", "Title: Python Crash Course\n", "Summary: A fast-paced, no-nonsense guide to programming in Python\n", "Publisher: no starch press\n", "Reviews: 42\n", "Authors: ['eric matthes']\n", - "Score: 0.5254088\n" + "Score: 0.52540874\n" ] } ], @@ -525,7 +547,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 16, "id": "WoE0yTchfj3A", "metadata": { "id": "WoE0yTchfj3A" @@ -536,16 +558,16 @@ "output_type": "stream", "text": [ "\n", - "ID: HwOa7osBiUNHLMdf3q2r\n", + "ID: caRpvY4BKY8PuI1qPluy\n", "Publication date: 2019-10-29\n", "Title: The Pragmatic Programmer: Your Journey to Mastery\n", "Summary: A guide to pragmatic programming for software engineers and developers\n", "Publisher: addison-wesley\n", "Reviews: 30\n", "Authors: ['andrew hunt', 'david thomas']\n", - "Score: 0.62065494\n", + "Score: 0.6206549\n", "\n", - "ID: JQOa7osBiUNHLMdf3q2r\n", + "ID: d6RpvY4BKY8PuI1qPluy\n", "Publication date: 1994-10-31\n", "Title: Design Patterns: Elements of Reusable Object-Oriented Software\n", "Summary: Guide to design patterns that can be used in any object-oriented language\n", @@ -570,6 +592,14 @@ "\n", "pretty_response(response)" ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d9edaa20-b8e8-4ce4-99b1-58b81de29dd5", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { @@ -591,7 +621,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.3" + "version": "3.10.13" } }, "nbformat": 4, diff --git a/x-pack/plugins/search_notebooks/server/data/01_keyword_querying_filtering.json b/x-pack/plugins/search_notebooks/server/data/01_keyword_querying_filtering.json index 308b65782a379..fa05b7d00bb10 100644 --- a/x-pack/plugins/search_notebooks/server/data/01_keyword_querying_filtering.json +++ b/x-pack/plugins/search_notebooks/server/data/01_keyword_querying_filtering.json @@ -8,7 +8,7 @@ "source": [ "# Keyword querying and filtering\n", "\n", - "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/elasticsearch-labs/blob/main/search/01-keyword-querying-filtering.ipynb)\n", + "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/elastic/elasticsearch-labs/blob/main/notebooks/search/01-keyword-querying-filtering.ipynb)\n", "\n", "This interactive notebook will introduce you to the basic Elasticsearch queries, using the official Elasticsearch Python client. Before getting started on this section you should work through our [quick start](https://github.com/elastic/elasticsearch-labs/blob/main/notebooks/search/00-quick-start.ipynb), as you will be using the same dataset." ] @@ -67,6 +67,44 @@ ")" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Enable Telemetry\n", + "\n", + "Knowing that you are using this notebook helps us decide where to invest our efforts to improve our products. We would like to ask you that you run the following code to let us gather anonymous usage statistics. See [telemetry.py](https://github.com/elastic/elasticsearch-labs/blob/main/telemetry/telemetry.py) for details. Thank you!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!curl -O -s https://raw.githubusercontent.com/elastic/elasticsearch-labs/main/telemetry/telemetry.py\n", + "from telemetry import enable_telemetry\n", + "\n", + "client = enable_telemetry(client, \"01-keyword-querying-filtering\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Test the Client\n", + "Before you continue, confirm that the client has connected with this test." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(client.info())" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -899,7 +937,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.3" + "version": "3.10.13" }, "vscode": { "interpreter": { diff --git a/x-pack/plugins/search_notebooks/server/data/02_hybrid_search.json b/x-pack/plugins/search_notebooks/server/data/02_hybrid_search.json index c5e9fd22caad6..3dbe93a3b15c2 100644 --- a/x-pack/plugins/search_notebooks/server/data/02_hybrid_search.json +++ b/x-pack/plugins/search_notebooks/server/data/02_hybrid_search.json @@ -115,6 +115,27 @@ ")" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Enable Telemetry\n", + "\n", + "Knowing that you are using this notebook helps us decide where to invest our efforts to improve our products. We would like to ask you that you run the following code to let us gather anonymous usage statistics. See [telemetry.py](https://github.com/elastic/elasticsearch-labs/blob/main/telemetry/telemetry.py) for details. Thank you!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!curl -O -s https://raw.githubusercontent.com/elastic/elasticsearch-labs/main/telemetry/telemetry.py\n", + "from telemetry import enable_telemetry\n", + "\n", + "client = enable_telemetry(client, \"02-hybrid-search\")" + ] + }, { "attachments": {}, "cell_type": "markdown", @@ -122,7 +143,8 @@ "id": "bRHbecNeEDL3" }, "source": [ - "Confirm that the client has connected with this test" + "### Test the Client\n", + "Before you continue, confirm that the client has connected with this test." ] }, { @@ -293,7 +315,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.3" + "version": "3.10.13" }, "vscode": { "interpreter": { diff --git a/x-pack/plugins/search_notebooks/server/data/03_elser.json b/x-pack/plugins/search_notebooks/server/data/03_elser.json index c6c5e6afcbc3f..303dfb3c8dcdd 100644 --- a/x-pack/plugins/search_notebooks/server/data/03_elser.json +++ b/x-pack/plugins/search_notebooks/server/data/03_elser.json @@ -117,6 +117,27 @@ ")" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Enable Telemetry\n", + "\n", + "Knowing that you are using this notebook helps us decide where to invest our efforts to improve our products. We would like to ask you that you run the following code to let us gather anonymous usage statistics. See [telemetry.py](https://github.com/elastic/elasticsearch-labs/blob/main/telemetry/telemetry.py) for details. Thank you!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!curl -O -s https://raw.githubusercontent.com/elastic/elasticsearch-labs/main/telemetry/telemetry.py\n", + "from telemetry import enable_telemetry\n", + "\n", + "client = enable_telemetry(client, \"03-ELSER\")" + ] + }, { "attachments": {}, "cell_type": "markdown", @@ -124,7 +145,8 @@ "id": "bRHbecNeEDL3" }, "source": [ - "Confirm that the client has connected with this test" + "### Test the Client\n", + "Before you continue, confirm that the client has connected with this test." ] }, { @@ -539,7 +561,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.6" + "version": "3.10.13" }, "vscode": { "interpreter": { diff --git a/x-pack/plugins/search_notebooks/server/data/04_multilingual.json b/x-pack/plugins/search_notebooks/server/data/04_multilingual.json index 9b41984a69035..5071f103759c4 100644 --- a/x-pack/plugins/search_notebooks/server/data/04_multilingual.json +++ b/x-pack/plugins/search_notebooks/server/data/04_multilingual.json @@ -255,6 +255,27 @@ ")" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Enable Telemetry\n", + "\n", + "Knowing that you are using this notebook helps us decide where to invest our efforts to improve our products. We would like to ask you that you run the following code to let us gather anonymous usage statistics. See [telemetry.py](https://github.com/elastic/elasticsearch-labs/blob/main/telemetry/telemetry.py) for details. Thank you!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!curl -O -s https://raw.githubusercontent.com/elastic/elasticsearch-labs/main/telemetry/telemetry.py\n", + "from telemetry import enable_telemetry\n", + "\n", + "client = enable_telemetry(client, \"04-multilingual\")" + ] + }, { "attachments": {}, "cell_type": "markdown", @@ -262,7 +283,8 @@ "id": "bRHbecNeEDL3" }, "source": [ - "Confirm that the client has connected with this test" + "### Test the Client\n", + "Before you continue, confirm that the client has connected with this test." ] }, { @@ -653,7 +675,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.3" + "version": "3.10.13" }, "vscode": { "interpreter": { diff --git a/x-pack/plugins/search_playground/public/chat_playground_overview.tsx b/x-pack/plugins/search_playground/public/chat_playground_overview.tsx index d40996ba91455..fc350356e873a 100644 --- a/x-pack/plugins/search_playground/public/chat_playground_overview.tsx +++ b/x-pack/plugins/search_playground/public/chat_playground_overview.tsx @@ -7,7 +7,7 @@ import { i18n } from '@kbn/i18n'; import React, { useMemo } from 'react'; -import { EuiBetaBadge, EuiFlexGroup, EuiFlexItem, EuiPageTemplate } from '@elastic/eui'; +import { EuiBetaBadge, EuiFlexGroup, EuiFlexItem, EuiPageTemplate, EuiTitle } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { PlaygroundProvider } from './providers/playground_provider'; @@ -27,11 +27,7 @@ export const ChatPlaygroundOverview: React.FC = () => { ); return ( - + { grow={false} > .euiFlexGroup': { flexWrap: 'wrap' } }} pageTitle={ - - - + +

+ +

+
{ component="form" css={{ display: 'flex', flexGrow: 1 }} onSubmit={handleSubmit(onSubmit)} + data-test-subj="chatPage" > { isLoading={isSubmitting} isDisabled={!isValid} iconType={TelegramIcon} + data-test-subj="sendQuestionButton" /> ) } diff --git a/x-pack/plugins/search_playground/public/components/edit_context/edit_context_action.tsx b/x-pack/plugins/search_playground/public/components/edit_context/edit_context_action.tsx index 45e956472bf9a..6e9a638248660 100644 --- a/x-pack/plugins/search_playground/public/components/edit_context/edit_context_action.tsx +++ b/x-pack/plugins/search_playground/public/components/edit_context/edit_context_action.tsx @@ -22,7 +22,11 @@ export const EditContextAction: React.FC = () => { return ( <> {showFlyout && } - setShowFlyout(true)} disabled={selectedIndices?.length === 0}> + setShowFlyout(true)} + disabled={selectedIndices?.length === 0} + data-test-subj="editContextActionButton" + > = ({ onClose }) }, [usageTracker]); return ( - +

@@ -172,6 +172,7 @@ export const EditContextFlyout: React.FC = ({ onClose }) options={group.source_fields.map((field) => ({ value: field, inputDisplay: field, + 'data-test-subj': 'contextField', }))} valueOfSelected={tempSourceFields[index]?.[0]} onChange={(value) => updateSourceField(index, value)} diff --git a/x-pack/plugins/search_playground/public/components/message_list/user_message.tsx b/x-pack/plugins/search_playground/public/components/message_list/user_message.tsx index b2ad7d6e1b647..12c1d86283404 100644 --- a/x-pack/plugins/search_playground/public/components/message_list/user_message.tsx +++ b/x-pack/plugins/search_playground/public/components/message_list/user_message.tsx @@ -57,6 +57,7 @@ export const UserMessage: React.FC = ({ content, createdAt }) })} /> } + data-test-subj="userMessage" >

{content}

diff --git a/x-pack/plugins/search_playground/public/components/question_input.tsx b/x-pack/plugins/search_playground/public/components/question_input.tsx index 0077e2ac7bf73..cdc9d347e4ff8 100644 --- a/x-pack/plugins/search_playground/public/components/question_input.tsx +++ b/x-pack/plugins/search_playground/public/components/question_input.tsx @@ -66,6 +66,7 @@ export const QuestionInput: React.FC = ({ onChange={handleChange} disabled={isDisabled} resize="none" + data-test-subj="questionInput" />
= ({ disabled: selectedIndices.includes(index), }))} isClearable={false} + data-test-subj="selectIndicesComboBox" /> ); diff --git a/x-pack/plugins/search_playground/public/components/sources_panel/sources_panel_for_start_chat.tsx b/x-pack/plugins/search_playground/public/components/sources_panel/sources_panel_for_start_chat.tsx index 5a270fe3d44dd..992ae7e574658 100644 --- a/x-pack/plugins/search_playground/public/components/sources_panel/sources_panel_for_start_chat.tsx +++ b/x-pack/plugins/search_playground/public/components/sources_panel/sources_panel_for_start_chat.tsx @@ -34,7 +34,7 @@ export const SourcesPanelForStartChat: React.FC = () => { defaultMessage: "Select the Elasticsearch indices you'd like to query, providing additional context for the LLM.", })} - isValid={!!selectedIndices.length} + isValid={!!selectedIndices?.length} dataTestSubj="selectIndicesChatPanel" > {!!selectedIndices?.length && ( diff --git a/x-pack/plugins/search_playground/public/components/start_new_chat.test.tsx b/x-pack/plugins/search_playground/public/components/start_new_chat.test.tsx new file mode 100644 index 0000000000000..ed380e00eb1da --- /dev/null +++ b/x-pack/plugins/search_playground/public/components/start_new_chat.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 { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; + +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { MemoryRouter, useSearchParams } from 'react-router-dom-v5-compat'; +import { StartNewChat } from './start_new_chat'; +import { useLoadConnectors } from '../hooks/use_load_connectors'; +import { useUsageTracker } from '../hooks/use_usage_tracker'; +import { AnalyticsEvents } from '../analytics/constants'; +import { useSourceIndicesFields } from '../hooks/use_source_indices_field'; +import { useKibana } from '../hooks/use_kibana'; +import { PlaygroundProvider } from '../providers/playground_provider'; + +jest.mock('../hooks/use_load_connectors'); +jest.mock('../hooks/use_usage_tracker'); +jest.mock('../hooks/use_source_indices_field', () => ({ + useSourceIndicesFields: jest.fn(() => ({ addIndex: jest.fn() })), +})); +jest.mock('react-router-dom-v5-compat', () => ({ + ...jest.requireActual('react-router-dom-v5-compat'), + useSearchParams: jest.fn(), +})); +jest.mock('../hooks/use_kibana'); + +const mockUseLoadConnectors = useLoadConnectors as jest.Mock; +const mockUseUsageTracker = useUsageTracker as jest.Mock; +const mockUseSearchParams = useSearchParams as jest.Mock; + +const renderWithForm = (ui: React.ReactElement) => { + const Wrapper: React.FC = ({ children }) => { + return ( + + {children} + + ); + }; + return render(ui, { wrapper: Wrapper }); +}; + +const mockConnectors = { + '1': { title: 'Connector 1' }, + '2': { title: 'Connector 2' }, +}; + +describe('StartNewChat', () => { + beforeEach(() => { + mockUseLoadConnectors.mockReturnValue({ data: [] }); + mockUseUsageTracker.mockReturnValue({ load: jest.fn() }); + mockUseSearchParams.mockReturnValue([new URLSearchParams()]); + + (useKibana as jest.Mock).mockReturnValue({ + services: { + triggersActionsUi: { + getAddConnectorFlyout: () => ( +
Add Connector Flyout
+ ), + }, + }, + }); + (useLoadConnectors as jest.Mock).mockReturnValue({ + data: mockConnectors, + refetch: jest.fn(), + isLoading: false, + isSuccess: true, + }); + }); + + it('renders correctly', () => { + renderWithForm( + + + + ); + + expect(screen.getByTestId('startNewChatTitle')).toBeInTheDocument(); + }); + + it('disables the start button when form conditions are not met', () => { + renderWithForm( + + + + ); + + const startButton = screen.getByTestId('startChatButton'); + expect(startButton).toBeDisabled(); + }); + + it('tracks the page load event', () => { + const usageTracker = { load: jest.fn() }; + mockUseUsageTracker.mockReturnValue(usageTracker); + + renderWithForm( + + + + ); + + expect(usageTracker.load).toHaveBeenCalledWith(AnalyticsEvents.startNewChatPageLoaded); + }); + + it('calls addIndex when default-index is present in searchParams', () => { + const addIndex = jest.fn(); + (useSourceIndicesFields as jest.Mock).mockReturnValue({ addIndex }); + const searchParams = new URLSearchParams({ 'default-index': 'test-index' }); + mockUseSearchParams.mockReturnValue([searchParams]); + + renderWithForm( + + + + ); + + expect(addIndex).toHaveBeenCalledWith('test-index'); + }); +}); diff --git a/x-pack/plugins/search_playground/public/components/start_new_chat.tsx b/x-pack/plugins/search_playground/public/components/start_new_chat.tsx index 0db891438cb3d..0df4485ec858c 100644 --- a/x-pack/plugins/search_playground/public/components/start_new_chat.tsx +++ b/x-pack/plugins/search_playground/public/components/start_new_chat.tsx @@ -15,14 +15,16 @@ import { useEuiTheme, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import React, { useEffect } from 'react'; +import React, { useEffect, useMemo } from 'react'; import { useFormContext } from 'react-hook-form'; +import { useSearchParams } from 'react-router-dom-v5-compat'; import { useUsageTracker } from '../hooks/use_usage_tracker'; import { useLoadConnectors } from '../hooks/use_load_connectors'; import { SourcesPanelForStartChat } from './sources_panel/sources_panel_for_start_chat'; import { SetUpConnectorPanelForStartChat } from './set_up_connector_panel_for_start_chat'; import { ChatFormFields } from '../types'; import { AnalyticsEvents } from '../analytics/constants'; +import { useSourceIndicesFields } from '../hooks/use_source_indices_field'; const maxWidthPage = 640; @@ -36,12 +38,23 @@ export const StartNewChat: React.FC = ({ onStartClick }) => { const { watch } = useFormContext(); const usageTracker = useUsageTracker(); + const [searchParams] = useSearchParams(); + const index = useMemo(() => searchParams.get('default-index'), [searchParams]); + const { addIndex } = useSourceIndicesFields(); + + useEffect(() => { + if (index) { + addIndex(index); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [index]); + useEffect(() => { usageTracker?.load(AnalyticsEvents.startNewChatPageLoaded); }, [usageTracker]); return ( - + = ({ onStartClick }) => { -

+

= ({ onStartClick }) => { - + { fill onClick={() => setShowFlyout(true)} disabled={!selectedIndices || selectedIndices?.length === 0} + data-test-subj="viewCodeActionButton" > = ({ onClose }) => { }, [usageTracker, selectedLanguage]); return ( - +

diff --git a/x-pack/plugins/search_playground/public/components/view_query/view_query_action.tsx b/x-pack/plugins/search_playground/public/components/view_query/view_query_action.tsx index 9b691283bab90..53d01dc81d614 100644 --- a/x-pack/plugins/search_playground/public/components/view_query/view_query_action.tsx +++ b/x-pack/plugins/search_playground/public/components/view_query/view_query_action.tsx @@ -20,7 +20,11 @@ export const ViewQueryAction: React.FC = () => { return ( <> {showFlyout && setShowFlyout(false)} />} - setShowFlyout(true)} disabled={selectedIndices?.length === 0}> + setShowFlyout(true)} + disabled={selectedIndices?.length === 0} + data-test-subj="viewQueryActionButton" + > = ({ onClose }) => }, [usageTracker]); return ( - +

@@ -216,6 +216,7 @@ export const ViewQueryFlyout: React.FC = ({ onClose }) => /> ), checked: checked ? 'on' : undefined, + 'data-test-subj': 'queryField', }; })} listProps={{ diff --git a/x-pack/plugins/search_playground/public/providers/playground_provider.tsx b/x-pack/plugins/search_playground/public/providers/playground_provider.tsx index 301bbfe89b2e4..562658b4b8bd5 100644 --- a/x-pack/plugins/search_playground/public/providers/playground_provider.tsx +++ b/x-pack/plugins/search_playground/public/providers/playground_provider.tsx @@ -8,25 +8,23 @@ import React, { FC, PropsWithChildren } from 'react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { FormProvider, useForm } from 'react-hook-form'; -import { ChatForm, ChatFormFields } from '../types'; +import { ChatForm } from '../types'; const queryClient = new QueryClient({}); export interface PlaygroundProviderProps { children: React.ReactNode; - defaultValues?: Partial>; } export const PlaygroundProvider: FC> = ({ children, - defaultValues, }) => { const form = useForm({ defaultValues: { prompt: 'You are an assistant for question-answering tasks.', doc_size: 3, source_fields: {}, - indices: defaultValues?.indices || [], + indices: [], }, }); diff --git a/x-pack/plugins/search_playground/server/lib/conversational_chain.test.ts b/x-pack/plugins/search_playground/server/lib/conversational_chain.test.ts index 8d4460f137736..8d67f6f03b8d1 100644 --- a/x-pack/plugins/search_playground/server/lib/conversational_chain.test.ts +++ b/x-pack/plugins/search_playground/server/lib/conversational_chain.test.ts @@ -9,19 +9,30 @@ import type { Client } from '@elastic/elasticsearch'; import { createAssist as Assist } from '../utils/assist'; import { ConversationalChain } from './conversational_chain'; import { FakeListChatModel } from '@langchain/core/utils/testing'; +import { FakeListLLM } from 'langchain/llms/fake'; import { BaseChatModel } from '@langchain/core/language_models/chat_models'; import { Message } from 'ai'; describe('conversational chain', () => { - const createTestChain = async ( - responses: string[], - chat: Message[], - expectedFinalAnswer: string, - expectedDocs: any, - expectedTokens: any, - expectedSearchRequest: any, - contentField: Record = { index: 'field', website: 'body_content' } - ) => { + const createTestChain = async ({ + responses, + chat, + expectedFinalAnswer, + expectedDocs, + expectedTokens, + expectedSearchRequest, + contentField = { index: 'field', website: 'body_content' }, + isChatModel = true, + }: { + responses: string[]; + chat: Message[]; + expectedFinalAnswer: string; + expectedDocs: any; + expectedTokens: any; + expectedSearchRequest: any; + contentField?: Record; + isChatModel?: boolean; + }) => { const searchMock = jest.fn().mockImplementation(() => { return { hits: { @@ -54,9 +65,11 @@ describe('conversational chain', () => { }, }; - const llm = new FakeListChatModel({ - responses, - }); + const llm = isChatModel + ? new FakeListChatModel({ + responses, + }) + : new FakeListLLM({ responses }); const aiClient = Assist({ es_client: mockElasticsearchClient as unknown as Client, @@ -118,17 +131,17 @@ describe('conversational chain', () => { }; it('should be able to create a conversational chain', async () => { - await createTestChain( - ['the final answer'], - [ + await createTestChain({ + responses: ['the final answer'], + chat: [ { id: '1', role: 'user', content: 'what is the work from home policy?', }, ], - 'the final answer', - [ + expectedFinalAnswer: 'the final answer', + expectedDocs: [ { documents: [ { metadata: { _id: '1', _index: 'index' }, pageContent: 'value' }, @@ -137,32 +150,32 @@ describe('conversational chain', () => { type: 'retrieved_docs', }, ], - [ + expectedTokens: [ { type: 'context_token_count', count: 15 }, { type: 'prompt_token_count', count: 5 }, ], - [ + expectedSearchRequest: [ { method: 'POST', path: '/index,website/_search', body: { query: { match: { field: 'what is the work from home policy?' } }, size: 3 }, }, - ] - ); + ], + }); }); it('should be able to create a conversational chain with nested field', async () => { - await createTestChain( - ['the final answer'], - [ + await createTestChain({ + responses: ['the final answer'], + chat: [ { id: '1', role: 'user', content: 'what is the work from home policy?', }, ], - 'the final answer', - [ + expectedFinalAnswer: 'the final answer', + expectedDocs: [ { documents: [ { metadata: { _id: '1', _index: 'index' }, pageContent: 'value' }, @@ -171,25 +184,25 @@ describe('conversational chain', () => { type: 'retrieved_docs', }, ], - [ + expectedTokens: [ { type: 'context_token_count', count: 15 }, { type: 'prompt_token_count', count: 5 }, ], - [ + expectedSearchRequest: [ { method: 'POST', path: '/index,website/_search', body: { query: { match: { field: 'what is the work from home policy?' } }, size: 3 }, }, ], - { index: 'field', website: 'metadata.source' } - ); + contentField: { index: 'field', website: 'metadata.source' }, + }); }); it('asking with chat history should re-write the question', async () => { - await createTestChain( - ['rewrite the question', 'the final answer'], - [ + await createTestChain({ + responses: ['rewrite the question', 'the final answer'], + chat: [ { id: '1', role: 'user', @@ -206,8 +219,8 @@ describe('conversational chain', () => { content: 'what is the work from home policy?', }, ], - 'the final answer', - [ + expectedFinalAnswer: 'the final answer', + expectedDocs: [ { documents: [ { metadata: { _id: '1', _index: 'index' }, pageContent: 'value' }, @@ -216,24 +229,24 @@ describe('conversational chain', () => { type: 'retrieved_docs', }, ], - [ + expectedTokens: [ { type: 'context_token_count', count: 15 }, { type: 'prompt_token_count', count: 5 }, ], - [ + expectedSearchRequest: [ { method: 'POST', path: '/index,website/_search', body: { query: { match: { field: 'rewrite the question' } }, size: 3 }, }, - ] - ); + ], + }); }); it('should cope with quotes in the query', async () => { - await createTestChain( - ['rewrite "the" question', 'the final answer'], - [ + await createTestChain({ + responses: ['rewrite "the" question', 'the final answer'], + chat: [ { id: '1', role: 'user', @@ -250,8 +263,8 @@ describe('conversational chain', () => { content: 'what is the work from home policy?', }, ], - 'the final answer', - [ + expectedFinalAnswer: 'the final answer', + expectedDocs: [ { documents: [ { metadata: { _id: '1', _index: 'index' }, pageContent: 'value' }, @@ -260,17 +273,62 @@ describe('conversational chain', () => { type: 'retrieved_docs', }, ], - [ + expectedTokens: [ { type: 'context_token_count', count: 15 }, { type: 'prompt_token_count', count: 5 }, ], - [ + expectedSearchRequest: [ { method: 'POST', path: '/index,website/_search', body: { query: { match: { field: 'rewrite "the" question' } }, size: 3 }, }, - ] - ); + ], + }); + }); + + it('should work with an LLM based model', async () => { + await createTestChain({ + responses: ['rewrite "the" question', 'the final answer'], + chat: [ + { + id: '1', + role: 'user', + content: 'what is the work from home policy?', + }, + { + id: '2', + role: 'assistant', + content: 'the final answer', + }, + { + id: '3', + role: 'user', + content: 'what is the work from home policy?', + }, + ], + expectedFinalAnswer: 'the final answer', + expectedDocs: [ + { + documents: [ + { metadata: { _id: '1', _index: 'index' }, pageContent: 'value' }, + { metadata: { _id: '1', _index: 'website' }, pageContent: 'value2' }, + ], + type: 'retrieved_docs', + }, + ], + expectedTokens: [ + { type: 'context_token_count', count: 15 }, + { type: 'prompt_token_count', count: 7 }, + ], + expectedSearchRequest: [ + { + method: 'POST', + path: '/index,website/_search', + body: { query: { match: { field: 'rewrite "the" question' } }, size: 3 }, + }, + ], + isChatModel: false, + }); }); }); diff --git a/x-pack/plugins/search_playground/server/lib/conversational_chain.ts b/x-pack/plugins/search_playground/server/lib/conversational_chain.ts index 1ec7bfb20c017..6080557e4c68f 100644 --- a/x-pack/plugins/search_playground/server/lib/conversational_chain.ts +++ b/x-pack/plugins/search_playground/server/lib/conversational_chain.ts @@ -150,6 +150,7 @@ class ConversationalChainFn { { callbacks: [ { + // callback for chat based models (OpenAI) handleChatModelStart( llm, msg: BaseMessage[][], @@ -166,6 +167,15 @@ class ConversationalChainFn { }); } }, + // callback for prompt based models (Bedrock uses ActionsClientLlm) + handleLLMStart(llm, input, runId, parentRunId, extraParams, tags, metadata) { + if (metadata?.type === 'question_answer_qa') { + data.appendMessageAnnotation({ + type: 'prompt_token_count', + count: getTokenEstimate(input[0]), + }); + } + }, handleRetrieverEnd(documents) { retrievedDocs.push(...documents); data.appendMessageAnnotation({ diff --git a/x-pack/plugins/search_playground/server/lib/get_chat_params.test.ts b/x-pack/plugins/search_playground/server/lib/get_chat_params.test.ts index cb409461d0a48..8eb46a2cdb7e4 100644 --- a/x-pack/plugins/search_playground/server/lib/get_chat_params.test.ts +++ b/x-pack/plugins/search_playground/server/lib/get_chat_params.test.ts @@ -6,10 +6,7 @@ */ import { getChatParams } from './get_chat_params'; -import { - ActionsClientChatOpenAI, - ActionsClientLlm, -} from '@kbn/elastic-assistant-common/impl/language_models'; +import { ActionsClientChatOpenAI, ActionsClientLlm } from '@kbn/langchain/server'; import { OPENAI_CONNECTOR_ID, BEDROCK_CONNECTOR_ID, @@ -18,10 +15,14 @@ import { Prompt } from '../../common/prompt'; import { KibanaRequest, Logger } from '@kbn/core/server'; import { PluginStartContract as ActionsPluginStartContract } from '@kbn/actions-plugin/server'; -jest.mock('@kbn/elastic-assistant-common/impl/language_models', () => ({ - ActionsClientChatOpenAI: jest.fn(), - ActionsClientLlm: jest.fn(), -})); +jest.mock('@kbn/langchain/server', () => { + const original = jest.requireActual('@kbn/langchain/server'); + return { + ...original, + ActionsClientChatOpenAI: jest.fn(), + ActionsClientLlm: jest.fn(), + }; +}); jest.mock('../../common/prompt', () => ({ Prompt: jest.fn((instructions) => instructions), @@ -84,7 +85,16 @@ describe('getChatParams', () => { context: true, type: 'anthropic', }); - expect(ActionsClientLlm).toHaveBeenCalledWith(expect.anything()); + expect(ActionsClientLlm).toHaveBeenCalledWith({ + temperature: 0, + llmType: 'bedrock', + traceId: 'test-uuid', + request: expect.anything(), + logger: expect.anything(), + model: 'custom-model', + connectorId: '2', + actions: expect.anything(), + }); expect(result.chatPrompt).toContain('How does it work?'); }); diff --git a/x-pack/plugins/search_playground/server/lib/get_chat_params.ts b/x-pack/plugins/search_playground/server/lib/get_chat_params.ts index 2dba42c668c77..a481309b9277d 100644 --- a/x-pack/plugins/search_playground/server/lib/get_chat_params.ts +++ b/x-pack/plugins/search_playground/server/lib/get_chat_params.ts @@ -6,16 +6,17 @@ */ import { OPENAI_CONNECTOR_ID } from '@kbn/stack-connectors-plugin/common/openai/constants'; -import { - ActionsClientChatOpenAI, - ActionsClientLlm, -} from '@kbn/elastic-assistant-common/impl/language_models'; import { v4 as uuidv4 } from 'uuid'; import { BEDROCK_CONNECTOR_ID } from '@kbn/stack-connectors-plugin/common/bedrock/constants'; import type { PluginStartContract as ActionsPluginStartContract } from '@kbn/actions-plugin/server'; import type { KibanaRequest, Logger } from '@kbn/core/server'; import { BaseLanguageModel } from '@langchain/core/language_models/base'; import type { Connector } from '@kbn/actions-plugin/server/application/connector/types'; +import { + ActionsClientChatOpenAI, + ActionsClientLlm, + getDefaultArguments, +} from '@kbn/langchain/server'; import { Prompt } from '../../common/prompt'; export const getChatParams = async ( @@ -52,6 +53,7 @@ export const getChatParams = async ( model, traceId: uuidv4(), signal: abortSignal, + temperature: getDefaultArguments().temperature, // prevents the agent from retrying on failure // failure could be due to bad connector, we should deliver that result to the client asap maxRetries: 0, @@ -63,6 +65,7 @@ export const getChatParams = async ( }); break; case BEDROCK_CONNECTOR_ID: + const llmType = 'bedrock'; chatModel = new ActionsClientLlm({ actions, logger, @@ -70,6 +73,8 @@ export const getChatParams = async ( connectorId, model, traceId: uuidv4(), + llmType, + temperature: getDefaultArguments(llmType).temperature, }); chatPrompt = Prompt(prompt, { citations, diff --git a/x-pack/plugins/search_playground/server/utils/get_value_for_selected_field.test.ts b/x-pack/plugins/search_playground/server/utils/get_value_for_selected_field.test.ts index fb52b6145ea1c..a13e51603cc7b 100644 --- a/x-pack/plugins/search_playground/server/utils/get_value_for_selected_field.test.ts +++ b/x-pack/plugins/search_playground/server/utils/get_value_for_selected_field.test.ts @@ -44,7 +44,7 @@ describe('getValueForSelectedField', () => { ); }); - test('should return undefined for missing key', () => { + test('should return empty string for missing key', () => { const hit = { _index: 'sample-index', _id: '8jSNY48B6iHEi98DL1C-', @@ -58,6 +58,23 @@ describe('getValueForSelectedField', () => { }, }; - expect(getValueForSelectedField(hit._source, 'metadata.sources')).toBeUndefined(); + expect(getValueForSelectedField(hit._source, 'metadata.sources')).toBe(''); + }); + + test('should return empty string for nested key', () => { + const hit = { + _index: 'sample-index', + _id: '8jSNY48B6iHEi98DL1C-', + _score: 0.7789394, + _source: { + test: 'The Shawshank Redemption', + metadata: { + source: + 'Over the course of several years, two convicts form a friendship, seeking consolation and, eventually, redemption through basic compassion', + }, + }, + }; + + expect(getValueForSelectedField(hit._source, 'bla.sources')).toBe(''); }); }); diff --git a/x-pack/plugins/search_playground/server/utils/get_value_for_selected_field.ts b/x-pack/plugins/search_playground/server/utils/get_value_for_selected_field.ts index 6aab9cafb387a..6a2044f2943e4 100644 --- a/x-pack/plugins/search_playground/server/utils/get_value_for_selected_field.ts +++ b/x-pack/plugins/search_playground/server/utils/get_value_for_selected_field.ts @@ -5,7 +5,8 @@ * 2.0. */ -// @ts-ignore -export const getValueForSelectedField = (source, path: string): string => { - return path.split('.').reduce((acc, key) => acc[key], source); +import { get } from 'lodash'; + +export const getValueForSelectedField = (source: unknown, path: string): string => { + return get(source, path, ''); }; diff --git a/x-pack/plugins/search_playground/tsconfig.json b/x-pack/plugins/search_playground/tsconfig.json index 96c2c1681008a..c75c9213103bf 100644 --- a/x-pack/plugins/search_playground/tsconfig.json +++ b/x-pack/plugins/search_playground/tsconfig.json @@ -32,7 +32,7 @@ "@kbn/stack-connectors-plugin", "@kbn/cases-plugin", "@kbn/triggers-actions-ui-plugin", - "@kbn/elastic-assistant-common", + "@kbn/langchain", "@kbn/logging", "@kbn/react-kibana-context-render", "@kbn/doc-links", diff --git a/x-pack/plugins/security/public/plugin.tsx b/x-pack/plugins/security/public/plugin.tsx index 9077db924f87c..429437e9fa39a 100644 --- a/x-pack/plugins/security/public/plugin.tsx +++ b/x-pack/plugins/security/public/plugin.tsx @@ -191,7 +191,7 @@ export class SecurityPlugin core: CoreStart, { management, share }: PluginStartDependencies ): SecurityPluginStart { - const { application, http, notifications, docLinks } = core; + const { application, http, notifications } = core; const { anonymousPaths } = http; const logoutUrl = getLogoutUrl(http); @@ -202,7 +202,7 @@ export class SecurityPlugin this.sessionTimeout = new SessionTimeout(core, notifications, sessionExpired, http, tenant); this.sessionTimeout.start(); - this.securityCheckupService.start({ http, notifications, docLinks }); + this.securityCheckupService.start(core); this.securityApiClients.userProfiles.start(); if (management) { diff --git a/x-pack/plugins/security/public/security_checkup/components/insecure_cluster_alert.tsx b/x-pack/plugins/security/public/security_checkup/components/insecure_cluster_alert.tsx index 34710ba650f54..71e1a53e7d2fb 100644 --- a/x-pack/plugins/security/public/security_checkup/components/insecure_cluster_alert.tsx +++ b/x-pack/plugins/security/public/security_checkup/components/insecure_cluster_alert.tsx @@ -16,26 +16,38 @@ import { import React, { useState } from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; -import type { DocLinksStart, MountPoint } from '@kbn/core/public'; +import type { + AnalyticsServiceStart, + DocLinksStart, + I18nStart, + MountPoint, + ThemeServiceStart, +} from '@kbn/core/public'; import { i18n } from '@kbn/i18n'; -import { FormattedMessage, I18nProvider } from '@kbn/i18n-react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; export const insecureClusterAlertTitle = i18n.translate( 'xpack.security.checkup.insecureClusterTitle', { defaultMessage: 'Your data is not secure' } ); -export const insecureClusterAlertText = ( - docLinks: DocLinksStart, - onDismiss: (persist: boolean) => void -) => +interface Deps { + docLinks: DocLinksStart; + analytics: Pick; + i18n: I18nStart; + theme: Pick; +} + +export const insecureClusterAlertText = (deps: Deps, onDismiss: (persist: boolean) => void) => ((e) => { + const { docLinks, ...startServices } = deps; const AlertText = () => { const [persist, setPersist] = useState(false); const enableSecurityDocLink = `${docLinks.links.security.elasticsearchEnableSecurity}?blade=kibanasecuritymessage`; return ( - +
-
+ ); }; diff --git a/x-pack/plugins/security/public/security_checkup/security_checkup_service.tsx b/x-pack/plugins/security/public/security_checkup/security_checkup_service.tsx index 26cdc410825c0..4818e3721818a 100644 --- a/x-pack/plugins/security/public/security_checkup/security_checkup_service.tsx +++ b/x-pack/plugins/security/public/security_checkup/security_checkup_service.tsx @@ -8,10 +8,13 @@ import { BehaviorSubject, combineLatest, distinctUntilChanged, from, map } from 'rxjs'; import type { + AnalyticsServiceStart, DocLinksStart, HttpSetup, HttpStart, + I18nStart, NotificationsStart, + ThemeServiceStart, Toast, } from '@kbn/core/public'; @@ -27,6 +30,9 @@ interface StartDeps { http: HttpStart; notifications: NotificationsStart; docLinks: DocLinksStart; + analytics: Pick; + i18n: I18nStart; + theme: Pick; } const DEFAULT_SECURITY_CHECKUP_STATE = Object.freeze({ @@ -63,7 +69,7 @@ export class SecurityCheckupService { } } - private initializeAlert({ http, notifications, docLinks }: StartDeps) { + private initializeAlert({ http, notifications, ...startServices }: StartDeps) { const appState$ = from(this.getSecurityCheckupState(http)); // 10 days is reasonably long enough to call "forever" for a page load. @@ -81,7 +87,7 @@ export class SecurityCheckupService { this.alertToast = notifications.toasts.addWarning( { title: insecureClusterAlertTitle, - text: insecureClusterAlertText(docLinks, (persist: boolean) => + text: insecureClusterAlertText(startServices, (persist: boolean) => this.setAlertVisibility(false, persist) ), iconType: 'warning', diff --git a/x-pack/plugins/security/server/routes/api_keys/update.ts b/x-pack/plugins/security/server/routes/api_keys/update.ts index ef999820c6cae..076e0448be11d 100644 --- a/x-pack/plugins/security/server/routes/api_keys/update.ts +++ b/x-pack/plugins/security/server/routes/api_keys/update.ts @@ -9,7 +9,12 @@ import type { estypes } from '@elastic/elasticsearch'; import { schema } from '@kbn/config-schema'; import type { TypeOf } from '@kbn/config-schema'; -import { elasticsearchRoleSchema, getKibanaRoleSchema } from '@kbn/security-plugin-types-server'; +import { + crossClusterApiKeySchema, + elasticsearchRoleSchema, + getKibanaRoleSchema, + restApiKeySchema, +} from '@kbn/security-plugin-types-server'; import type { RouteDefinitionParams } from '..'; import { UpdateApiKeyValidationError } from '../../authentication/api_keys/api_keys'; @@ -29,56 +34,29 @@ export type UpdateAPIKeyParams = | UpdateCrossClusterAPIKeyParams | UpdateRestAPIKeyWithKibanaPrivilegesParams; -export type UpdateRestAPIKeyParams = TypeOf; -export type UpdateCrossClusterAPIKeyParams = TypeOf; -export type UpdateRestAPIKeyWithKibanaPrivilegesParams = TypeOf< - ReturnType ->; - -const restApiKeySchema = schema.object({ - type: schema.maybe(schema.literal('rest')), +const updateRestApiKeySchema = restApiKeySchema.extends({ + name: null, id: schema.string(), - role_descriptors: schema.recordOf(schema.string(), schema.object({}, { unknowns: 'allow' }), { - defaultValue: {}, - }), - metadata: schema.maybe(schema.object({}, { unknowns: 'allow' })), }); -const crossClusterApiKeySchema = restApiKeySchema.extends({ - type: schema.literal('cross_cluster'), - role_descriptors: null, - access: schema.object( - { - search: schema.maybe( - schema.arrayOf( - schema.object( - { - names: schema.arrayOf(schema.string()), - }, - { unknowns: 'allow' } - ) - ) - ), - replication: schema.maybe( - schema.arrayOf( - schema.object( - { - names: schema.arrayOf(schema.string()), - }, - { unknowns: 'allow' } - ) - ) - ), - }, - { unknowns: 'allow' } - ), +const updateCrossClusterApiKeySchema = crossClusterApiKeySchema.extends({ + name: null, + id: schema.string(), }); +export type UpdateRestAPIKeyParams = TypeOf; +export type UpdateCrossClusterAPIKeyParams = TypeOf; +export type UpdateRestAPIKeyWithKibanaPrivilegesParams = TypeOf< + ReturnType +>; + const getRestApiKeyWithKibanaPrivilegesSchema = ( getBasePrivilegeNames: Parameters[0] ) => restApiKeySchema.extends({ role_descriptors: null, + name: null, + id: schema.string(), kibana_role_descriptors: schema.recordOf( schema.string(), schema.object({ @@ -106,8 +84,8 @@ export function defineUpdateApiKeyRoutes({ path: '/internal/security/api_key', validate: { body: schema.oneOf([ - restApiKeySchema, - crossClusterApiKeySchema, + updateRestApiKeySchema, + updateCrossClusterApiKeySchema, bodySchemaWithKibanaPrivileges, ]), }, diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/common/common.gen.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/common/common.gen.ts index b037534248042..f17cb2a5ee0fb 100644 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/common/common.gen.ts +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/common/common.gen.ts @@ -155,8 +155,8 @@ export const RiskScoreWeightGlobalShared = z.object({ type: z.literal('global_identifier'), }); -export type RiskScoreWeightGlobal = z.infer; -export const RiskScoreWeightGlobal = z.union([ +export type RiskScoreWeight = z.infer; +export const RiskScoreWeight = z.union([ RiskScoreWeightGlobalShared.merge( z.object({ host: RiskScoreEntityIdentifierWeights, @@ -171,34 +171,6 @@ export const RiskScoreWeightGlobal = z.union([ ), ]); -export type RiskScoreWeightCategoryShared = z.infer; -export const RiskScoreWeightCategoryShared = z.object({ - type: z.literal('risk_category'), - value: RiskScoreCategories, -}); - -export type RiskScoreWeightCategory = z.infer; -export const RiskScoreWeightCategory = z.union([ - RiskScoreWeightCategoryShared.merge( - z.object({ - host: RiskScoreEntityIdentifierWeights, - user: RiskScoreEntityIdentifierWeights.optional(), - }) - ), - RiskScoreWeightCategoryShared.merge( - z.object({ - host: RiskScoreEntityIdentifierWeights.optional(), - user: RiskScoreEntityIdentifierWeights, - }) - ), -]); - -/** - * Configuration used to tune risk scoring. Weights can be used to change the score contribution of risk inputs for hosts and users at both a global level and also for Risk Input categories (e.g. 'category_1'). - */ -export type RiskScoreWeight = z.infer; -export const RiskScoreWeight = z.union([RiskScoreWeightGlobal, RiskScoreWeightCategory]); - /** * A list of weights to be applied to the scoring calculation. */ diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/common/common.schema.yaml b/x-pack/plugins/security_solution/common/api/entity_analytics/common/common.schema.yaml index 7b6634876d8a6..63aa739d2133d 100644 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/common/common.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/common/common.schema.yaml @@ -201,7 +201,7 @@ components: enum: - global_identifier - RiskScoreWeightGlobal: + RiskScoreWeight: oneOf: - allOf: - $ref: '#/components/schemas/RiskScoreWeightGlobalShared' @@ -225,65 +225,12 @@ components: user: $ref: '#/components/schemas/RiskScoreEntityIdentifierWeights' - RiskScoreWeightCategoryShared: - x-inline: true - type: object - required: - - type - - value - properties: - type: - type: string - enum: - - risk_category - value: - $ref: '#/components/schemas/RiskScoreCategories' - - RiskScoreWeightCategory: - oneOf: - - allOf: - - $ref: '#/components/schemas/RiskScoreWeightCategoryShared' - - type: object - required: - - host - properties: - host: - $ref: '#/components/schemas/RiskScoreEntityIdentifierWeights' - user: - $ref: '#/components/schemas/RiskScoreEntityIdentifierWeights' - - - allOf: - - $ref: '#/components/schemas/RiskScoreWeightCategoryShared' - - type: object - required: - - user - properties: - host: - $ref: '#/components/schemas/RiskScoreEntityIdentifierWeights' - user: - $ref: '#/components/schemas/RiskScoreEntityIdentifierWeights' - - RiskScoreWeight: - description: "Configuration used to tune risk scoring. Weights can be used to change the score contribution of risk inputs for hosts and users at both a global level and also for Risk Input categories (e.g. 'category_1')." - oneOf: - - $ref: '#/components/schemas/RiskScoreWeightGlobal' - - $ref: '#/components/schemas/RiskScoreWeightCategory' - example: - type: 'risk_category' - value: 'category_1' - host: 0.8 - user: 0.4 - RiskScoreWeights: description: 'A list of weights to be applied to the scoring calculation.' type: array items: $ref: '#/components/schemas/RiskScoreWeight' example: - - type: 'risk_category' - value: 'category_1' - host: 0.8 - user: 0.4 - type: 'global_identifier' host: 0.5 user: 0.1 diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/common/risk_weights.schema.test.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/common/risk_weights.schema.test.ts index 59b0859300f88..e4afc38badd24 100644 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/common/risk_weights.schema.test.ts +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/common/risk_weights.schema.test.ts @@ -59,9 +59,7 @@ describe('risk weight schema', () => { const decoded = RiskScoreWeight.safeParse(payload) as SafeParseError; expect(decoded.success).toBeFalsy(); - expect(stringifyZodError(decoded.error)).toEqual( - 'host: Required, user: Required, type: Invalid literal value, expected "risk_category", value: Invalid literal value, expected "category_1", host: Required, and 3 more' - ); + expect(stringifyZodError(decoded.error)).toContain('host: Required, user: Required'); }); it('allows a single host weight', () => { @@ -123,44 +121,10 @@ describe('risk weight schema', () => { expect(decoded.success).toBeFalsy(); expect(stringifyZodError(decoded.error)).toEqual( - 'type: Invalid literal value, expected "global_identifier", host: Required, type: Invalid literal value, expected "global_identifier", value: Invalid literal value, expected "category_1", host: Required, and 1 more' + 'type: Invalid literal value, expected "global_identifier", host: Required, type: Invalid literal value, expected "global_identifier"' ); }); - it('rejects if neither host nor user weight are specified', () => { - const payload = { type, value: RiskCategories.category_1 }; - const decoded = RiskScoreWeight.safeParse(payload) as SafeParseError; - - expect(decoded.success).toBeFalsy(); - expect(stringifyZodError(decoded.error)).toEqual( - 'type: Invalid literal value, expected "global_identifier", host: Required, type: Invalid literal value, expected "global_identifier", user: Required, host: Required, and 1 more' - ); - }); - - it('allows a single host weight', () => { - const payload = { type, value: RiskCategories.category_1, host: 0.1 }; - const decoded = RiskScoreWeight.safeParse(payload) as SafeParseSuccess; - - expect(decoded.success).toBeTruthy(); - expect(decoded.data).toEqual(payload); - }); - - it('allows a single user weight', () => { - const payload = { type, value: RiskCategories.category_1, user: 0.1 }; - const decoded = RiskScoreWeight.safeParse(payload) as SafeParseSuccess; - - expect(decoded.success).toBeTruthy(); - expect(decoded.data).toEqual(payload); - }); - - it('allows both a host and user weight', () => { - const payload = { type, value: RiskCategories.category_1, user: 0.1, host: 0.5 }; - const decoded = RiskScoreWeight.safeParse(payload) as SafeParseSuccess; - - expect(decoded.success).toBeTruthy(); - expect(decoded.data).toEqual(payload); - }); - it('rejects a weight outside of 0-1', () => { const payload = { type, value: RiskCategories.category_1, host: -5 }; const decoded = RiskScoreWeight.safeParse(payload) as SafeParseError; @@ -170,47 +134,6 @@ describe('risk weight schema', () => { `host: Number must be greater than or equal to 0` ); }); - - it('removes extra keys if specified', () => { - const payload = { - type, - value: RiskCategories.category_1, - host: 0.1, - extra: 'even more', - }; - const decoded = RiskScoreWeight.safeParse(payload) as SafeParseSuccess; - - expect(decoded.success).toBeTruthy(); - expect(decoded.data).toEqual({ type, value: RiskCategories.category_1, host: 0.1 }); - }); - - describe('allowed category values', () => { - it('allows the alerts type for a category', () => { - const payload = { - type, - value: RiskCategories.category_1, - host: 0.1, - }; - const decoded = RiskScoreWeight.safeParse(payload) as SafeParseSuccess; - - expect(decoded.success).toBeTruthy(); - expect(decoded.data).toEqual(payload); - }); - - it('rejects an unknown category value', () => { - const payload = { - type, - value: 'unknown', - host: 0.1, - }; - const decoded = RiskScoreWeight.safeParse(payload) as SafeParseError; - - expect(decoded.success).toBeFalsy(); - expect(stringifyZodError(decoded.error)).toContain( - 'type: Invalid literal value, expected "global_identifier", type: Invalid literal value, expected "global_identifier", user: Required, value: Invalid literal value, expected "category_1", value: Invalid literal value, expected "category_1", and 1 more' - ); - }); - }); }); }); }); diff --git a/x-pack/plugins/security_solution/common/endpoint/data_loaders/setup_fleet_for_endpoint.ts b/x-pack/plugins/security_solution/common/endpoint/data_loaders/setup_fleet_for_endpoint.ts index 12505dc87a2b0..e9da1b9a4df8c 100644 --- a/x-pack/plugins/security_solution/common/endpoint/data_loaders/setup_fleet_for_endpoint.ts +++ b/x-pack/plugins/security_solution/common/endpoint/data_loaders/setup_fleet_for_endpoint.ts @@ -29,10 +29,6 @@ import { wrapErrorAndRejectPromise, } from './utils'; -export interface SetupFleetForEndpointResponse { - endpointPackage: BulkInstallPackageInfo; -} - /** * Calls the fleet setup APIs and then installs the latest Endpoint package * @param kbnClient @@ -43,7 +39,7 @@ export const setupFleetForEndpoint = usageTracker.track( async (kbnClient: KbnClient, logger?: ToolingLog): Promise => { const log = logger ?? createToolingLogger(); - log.info(`setupFleetForEndpoint(): Setting up fleet for endpoint`); + log.debug(`setupFleetForEndpoint(): Setting up fleet for endpoint`); // Setup Fleet try { diff --git a/x-pack/plugins/security_solution/common/endpoint/format_axios_error.ts b/x-pack/plugins/security_solution/common/endpoint/format_axios_error.ts index 1f0c7da3bbad6..fa46f7940c17e 100644 --- a/x-pack/plugins/security_solution/common/endpoint/format_axios_error.ts +++ b/x-pack/plugins/security_solution/common/endpoint/format_axios_error.ts @@ -22,15 +22,18 @@ export class FormattedAxiosError extends Error { }; constructor(axiosError: AxiosError) { + const method = axiosError.config?.method ?? ''; + const url = axiosError.config?.url ?? ''; + super( `${axiosError.message}${ axiosError?.response?.data ? `: ${JSON.stringify(axiosError?.response?.data)}` : '' - }` + }${url ? `\n(Request: ${method} ${url})` : ''}` ); this.request = { - method: axiosError.config?.method ?? '?', - url: axiosError.config?.url ?? '?', + method, + url, data: axiosError.config?.data ?? '', }; diff --git a/x-pack/plugins/security_solution/common/endpoint/service/authz/authz.test.ts b/x-pack/plugins/security_solution/common/endpoint/service/authz/authz.test.ts index b5e4e874c7537..3772635ef2d33 100644 --- a/x-pack/plugins/security_solution/common/endpoint/service/authz/authz.test.ts +++ b/x-pack/plugins/security_solution/common/endpoint/service/authz/authz.test.ts @@ -155,6 +155,7 @@ describe('Endpoint Authz service', () => { ['canSuspendProcess', 'writeProcessOperations'], ['canGetRunningProcesses', 'writeProcessOperations'], ['canWriteExecuteOperations', 'writeExecuteOperations'], + ['canWriteScanOperations', 'writeScanOperations'], ['canWriteFileOperations', 'writeFileOperations'], ['canWriteTrustedApplications', 'writeTrustedApplications'], ['canReadTrustedApplications', 'readTrustedApplications'], @@ -193,6 +194,7 @@ describe('Endpoint Authz service', () => { ['canSuspendProcess', ['writeProcessOperations']], ['canGetRunningProcesses', ['writeProcessOperations']], ['canWriteExecuteOperations', ['writeExecuteOperations']], + ['canWriteScanOperations', ['writeScanOperations']], ['canWriteFileOperations', ['writeFileOperations']], ['canWriteTrustedApplications', ['writeTrustedApplications']], ['canReadTrustedApplications', ['readTrustedApplications']], @@ -242,6 +244,7 @@ describe('Endpoint Authz service', () => { ['canSuspendProcess', ['writeProcessOperations']], ['canGetRunningProcesses', ['writeProcessOperations']], ['canWriteExecuteOperations', ['writeExecuteOperations']], + ['canWriteScanOperations', ['writeScanOperations']], ['canWriteFileOperations', ['writeFileOperations']], ['canWriteTrustedApplications', ['writeTrustedApplications']], ['canReadTrustedApplications', ['readTrustedApplications']], @@ -317,6 +320,7 @@ describe('Endpoint Authz service', () => { canGetRunningProcesses: false, canAccessResponseConsole: false, canWriteExecuteOperations: false, + canWriteScanOperations: false, canWriteFileOperations: false, canWriteTrustedApplications: false, canReadTrustedApplications: false, diff --git a/x-pack/plugins/security_solution/common/endpoint/service/authz/authz.ts b/x-pack/plugins/security_solution/common/endpoint/service/authz/authz.ts index 95430a6df82fb..7b058e543e28f 100644 --- a/x-pack/plugins/security_solution/common/endpoint/service/authz/authz.ts +++ b/x-pack/plugins/security_solution/common/endpoint/service/authz/authz.ts @@ -53,6 +53,7 @@ function hasAuthFactory(fleetAuthz: FleetAuthz, productFeatureService?: ProductF * @param licenseService * @param fleetAuthz * @param userRoles + * @param productFeaturesService */ export const calculateEndpointAuthz = ( licenseService: LicenseService, @@ -90,6 +91,7 @@ export const calculateEndpointAuthz = ( const canWriteFileOperations = hasAuth('writeFileOperations'); const canWriteExecuteOperations = hasAuth('writeExecuteOperations'); + const canWriteScanOperations = hasAuth('writeScanOperations'); const canReadEndpointExceptions = hasAuth('showEndpointExceptions'); const canWriteEndpointExceptions = hasAuth('crudEndpointExceptions'); @@ -122,6 +124,7 @@ export const calculateEndpointAuthz = ( canAccessResponseConsole: false, // set further below canWriteExecuteOperations: canWriteExecuteOperations && isEnterpriseLicense, canWriteFileOperations: canWriteFileOperations && isEnterpriseLicense, + canWriteScanOperations: canWriteScanOperations && isEnterpriseLicense, // --------------------------------------------------------- // artifacts @@ -180,6 +183,7 @@ export const getEndpointAuthzInitialState = (): EndpointAuthz => { canAccessResponseConsole: false, canWriteFileOperations: false, canWriteExecuteOperations: false, + canWriteScanOperations: false, canWriteTrustedApplications: false, canReadTrustedApplications: false, canWriteHostIsolationExceptions: false, diff --git a/x-pack/plugins/security_solution/common/endpoint/service/response_actions/constants.ts b/x-pack/plugins/security_solution/common/endpoint/service/response_actions/constants.ts index 6e6b6de839344..02716e09a882a 100644 --- a/x-pack/plugins/security_solution/common/endpoint/service/response_actions/constants.ts +++ b/x-pack/plugins/security_solution/common/endpoint/service/response_actions/constants.ts @@ -27,6 +27,8 @@ export const RESPONSE_ACTION_API_COMMANDS_NAMES = [ 'get-file', 'execute', 'upload', + // TODO: for API changes in a subsequent PR + // 'scan', ] as const; export type ResponseActionsApiCommandNames = typeof RESPONSE_ACTION_API_COMMANDS_NAMES[number]; @@ -52,6 +54,8 @@ export const ENDPOINT_CAPABILITIES = [ 'get_file', 'execute', 'upload_file', + // TODO: for API changes in a subsequent PR + // 'scan', ] as const; export type EndpointCapabilities = typeof ENDPOINT_CAPABILITIES[number]; @@ -69,6 +73,8 @@ export const CONSOLE_RESPONSE_ACTION_COMMANDS = [ 'get-file', 'execute', 'upload', + // TODO: for API changes in a subsequent PR + // 'scan', ] as const; export type ConsoleResponseActionCommands = typeof CONSOLE_RESPONSE_ACTION_COMMANDS[number]; @@ -78,7 +84,8 @@ export type ResponseConsoleRbacControls = | 'writeHostIsolationRelease' | 'writeProcessOperations' | 'writeFileOperations' - | 'writeExecuteOperations'; + | 'writeExecuteOperations' + | 'writeScanOperations'; /** * maps the console command to the RBAC control (kibana feature control) that is required to access it via console @@ -95,6 +102,8 @@ export const RESPONSE_CONSOLE_ACTION_COMMANDS_TO_RBAC_FEATURE_CONTROL: Record< 'get-file': 'writeFileOperations', execute: 'writeExecuteOperations', upload: 'writeFileOperations', + // TODO: for API changes in a subsequent PR + // scan: 'writeScanOperations', }); export const RESPONSE_ACTION_API_COMMAND_TO_CONSOLE_COMMAND_MAP = Object.freeze< @@ -108,6 +117,8 @@ export const RESPONSE_ACTION_API_COMMAND_TO_CONSOLE_COMMAND_MAP = Object.freeze< 'kill-process': 'kill-process', 'suspend-process': 'suspend-process', upload: 'upload', + // TODO: for API changes in a subsequent PR + // scan: 'scan', }); export const RESPONSE_CONSOLE_COMMAND_TO_API_COMMAND_MAP = Object.freeze< @@ -121,6 +132,8 @@ export const RESPONSE_CONSOLE_COMMAND_TO_API_COMMAND_MAP = Object.freeze< 'kill-process': 'kill-process', 'suspend-process': 'suspend-process', upload: 'upload', + // TODO: for API changes in a subsequent PR + // scan: 'scan', }); export const RESPONSE_CONSOLE_ACTION_COMMANDS_TO_ENDPOINT_CAPABILITY = Object.freeze< @@ -134,6 +147,8 @@ export const RESPONSE_CONSOLE_ACTION_COMMANDS_TO_ENDPOINT_CAPABILITY = Object.fr 'kill-process': 'kill_process', 'suspend-process': 'suspend_process', upload: 'upload_file', + // TODO: for API changes in a subsequent PR + // scan: 'scan', }); /** @@ -150,6 +165,8 @@ export const RESPONSE_CONSOLE_ACTION_COMMANDS_TO_REQUIRED_AUTHZ = Object.freeze< processes: 'canGetRunningProcesses', 'kill-process': 'canKillProcess', 'suspend-process': 'canSuspendProcess', + // TODO: for API changes in a subsequent PR + // scan: 'canWriteScanOperations', }); // 4 hrs in seconds diff --git a/x-pack/plugins/security_solution/common/endpoint/types/authz.ts b/x-pack/plugins/security_solution/common/endpoint/types/authz.ts index 0ccefaa686f72..6a326479ce8ae 100644 --- a/x-pack/plugins/security_solution/common/endpoint/types/authz.ts +++ b/x-pack/plugins/security_solution/common/endpoint/types/authz.ts @@ -56,6 +56,8 @@ export interface EndpointAuthz { canWriteExecuteOperations: boolean; /** If the user has write permissions to use file operations */ canWriteFileOperations: boolean; + /** If user has write permission to use scan file path operations */ + canWriteScanOperations: boolean; /** If the user has write permissions for trusted applications */ canWriteTrustedApplications: boolean; /** If the user has read permissions for trusted applications */ diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index 565177fa8b560..01f03d4ac09ea 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -84,7 +84,7 @@ export const allowedExperimentalValues = Object.freeze({ * * Release: v8.14.0 */ - responseActionsSentinelOneV2Enabled: false, + responseActionsSentinelOneV2Enabled: true, /** Enables the `get-file` response action for SentinelOne */ responseActionsSentinelOneGetFileEnabled: false, @@ -102,6 +102,11 @@ export const allowedExperimentalValues = Object.freeze({ */ responseActionsCrowdstrikeManualHostIsolationEnabled: false, + /** + * Enables scan response action on Endpoint + */ + responseActionScanEnabled: false, + /** * Enables top charts on Alerts Page */ @@ -138,6 +143,11 @@ export const allowedExperimentalValues = Object.freeze({ */ assistantModelEvaluation: false, + /** + * Enables the Assistant Knowledge Base by default, introduced in `8.15.0`. + */ + assistantKnowledgeBaseByDefault: false, + /** * Enables the new user details flyout displayed on the Alerts table. */ diff --git a/x-pack/plugins/security_solution/public/assistant/content/prompts/system/translations.ts b/x-pack/plugins/security_solution/public/assistant/content/prompts/system/translations.ts index 63fcd9c9995a9..b132a8e83770a 100644 --- a/x-pack/plugins/security_solution/public/assistant/content/prompts/system/translations.ts +++ b/x-pack/plugins/security_solution/public/assistant/content/prompts/system/translations.ts @@ -15,13 +15,6 @@ export const YOU_ARE_A_HELPFUL_EXPERT_ASSISTANT = i18n.translate( } ); -export const USE_THE_FOLLOWING_CONTEXT_TO_ANSWER = i18n.translate( - 'xpack.securitySolution.assistant.content.prompts.system.useTheFollowingContextToAnswer', - { - defaultMessage: 'Use the following context to answer questions:', - } -); - export const IF_YOU_DONT_KNOW_THE_ANSWER = i18n.translate( 'xpack.securitySolution.assistant.content.prompts.system.ifYouDontKnowTheAnswer', { @@ -46,8 +39,7 @@ export const FORMAT_OUTPUT_CORRECTLY = i18n.translate( ); export const DEFAULT_SYSTEM_PROMPT_NON_I18N = `${YOU_ARE_A_HELPFUL_EXPERT_ASSISTANT} ${IF_YOU_DONT_KNOW_THE_ANSWER} -${FORMAT_OUTPUT_CORRECTLY} -${USE_THE_FOLLOWING_CONTEXT_TO_ANSWER}`; +${FORMAT_OUTPUT_CORRECTLY}`; export const DEFAULT_SYSTEM_PROMPT_NAME = i18n.translate( 'xpack.securitySolution.assistant.content.prompts.system.defaultSystemPromptName', @@ -58,8 +50,7 @@ export const DEFAULT_SYSTEM_PROMPT_NAME = i18n.translate( export const SUPERHERO_SYSTEM_PROMPT_NON_I18N = `${YOU_ARE_A_HELPFUL_EXPERT_ASSISTANT} ${IF_YOU_DONT_KNOW_THE_ANSWER} ${SUPERHERO_PERSONALITY} -${FORMAT_OUTPUT_CORRECTLY} -${USE_THE_FOLLOWING_CONTEXT_TO_ANSWER}`; +${FORMAT_OUTPUT_CORRECTLY}`; export const SUPERHERO_SYSTEM_PROMPT_NAME = i18n.translate( 'xpack.securitySolution.assistant.content.prompts.system.superheroSystemPromptName', @@ -67,7 +58,3 @@ export const SUPERHERO_SYSTEM_PROMPT_NAME = i18n.translate( defaultMessage: 'Enhanced system prompt', } ); - -export const SYSTEM_PROMPT_CONTEXT_NON_I18N = (context: string) => { - return `CONTEXT:\n"""\n${context}\n"""`; -}; diff --git a/x-pack/plugins/security_solution/public/assistant/provider.test.tsx b/x-pack/plugins/security_solution/public/assistant/provider.test.tsx index 9ee276181b65e..3667e077a50c1 100644 --- a/x-pack/plugins/security_solution/public/assistant/provider.test.tsx +++ b/x-pack/plugins/security_solution/public/assistant/provider.test.tsx @@ -165,7 +165,7 @@ describe('createConversations', () => { ); await waitForNextUpdate(); expect(http.fetch.mock.calls[0][0]).toBe( - '/api/elastic_assistant/current_user/conversations/_bulk_action' + '/internal/elastic_assistant/current_user/conversations/_bulk_action' ); expect( http.fetch.mock.calls[0].length > 1 @@ -187,7 +187,7 @@ describe('createConversations', () => { ); await waitForNextUpdate(); expect(http.fetch.mock.calls[0][0]).toBe( - '/api/elastic_assistant/current_user/conversations/_bulk_action' + '/internal/elastic_assistant/current_user/conversations/_bulk_action' ); const createdConversations = http.fetch.mock.calls[0].length > 1 diff --git a/x-pack/plugins/security_solution/public/common/components/agents/agent_status/agent_status.tsx b/x-pack/plugins/security_solution/public/common/components/agents/agent_status/agent_status.tsx index 05c5941e4575f..363e233baab59 100644 --- a/x-pack/plugins/security_solution/public/common/components/agents/agent_status/agent_status.tsx +++ b/x-pack/plugins/security_solution/public/common/components/agents/agent_status/agent_status.tsx @@ -16,7 +16,6 @@ import { HOST_STATUS_TO_BADGE_COLOR } from '../../../../management/pages/endpoin import { useIsExperimentalFeatureEnabled } from '../../../hooks/use_experimental_features'; import { getAgentStatusText } from '../agent_status_text'; import { AgentResponseActionsStatus } from './agent_response_action_status'; - export enum SENTINEL_ONE_NETWORK_STATUS { CONNECTING = 'connecting', CONNECTED = 'connected', @@ -46,9 +45,12 @@ export const AgentStatus = React.memo( const sentinelOneManualHostActionsEnabled = useIsExperimentalFeatureEnabled( 'sentinelOneManualHostActionsEnabled' ); - + const responseActionsCrowdstrikeManualHostIsolationEnabled = useIsExperimentalFeatureEnabled( + 'responseActionsCrowdstrikeManualHostIsolationEnabled' + ); const { data, isLoading, isFetched } = useAgentStatus([agentId], agentType, { - enabled: sentinelOneManualHostActionsEnabled, + enabled: + sentinelOneManualHostActionsEnabled || responseActionsCrowdstrikeManualHostIsolationEnabled, }); const agentStatus = data?.[`${agentId}`]; const isCurrentlyIsolated = Boolean(agentStatus?.isolated); diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/alert_summary_view.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/alert_summary_view.tsx index 383f98f964242..74971bfb90162 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/alert_summary_view.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/alert_summary_view.tsx @@ -5,13 +5,12 @@ * 2.0. */ -import React, { useMemo } from 'react'; +import React from 'react'; import type { TimelineEventsDetailsItem } from '../../../../common/search_strategy'; import type { BrowserFields } from '../../../../common/search_strategy/index_fields'; -import { getSummaryRows } from './get_alert_summary_rows'; +import { useSummaryRows } from './get_alert_summary_rows'; import { SummaryView } from './summary_view'; -import { useIsExperimentalFeatureEnabled } from '../../hooks/use_experimental_features'; const AlertSummaryViewComponent: React.FC<{ browserFields: BrowserFields; @@ -34,33 +33,15 @@ const AlertSummaryViewComponent: React.FC<{ isReadOnly, investigationFields, }) => { - const sentinelOneManualHostActionsEnabled = useIsExperimentalFeatureEnabled( - 'sentinelOneManualHostActionsEnabled' - ); - - const summaryRows = useMemo( - () => - getSummaryRows({ - browserFields, - data, - eventId, - isDraggable, - scopeId, - isReadOnly, - investigationFields, - sentinelOneManualHostActionsEnabled, - }), - [ - browserFields, - data, - eventId, - isDraggable, - scopeId, - isReadOnly, - investigationFields, - sentinelOneManualHostActionsEnabled, - ] - ); + const summaryRows = useSummaryRows({ + browserFields, + data, + eventId, + isDraggable, + scopeId, + isReadOnly, + investigationFields, + }); return ( diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/get_alert_summary_rows.test.ts b/x-pack/plugins/security_solution/public/common/components/event_details/get_alert_summary_rows.test.ts new file mode 100644 index 0000000000000..60bc2b7f3ce31 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/event_details/get_alert_summary_rows.test.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 { isAlertFromEndpointEvent } from '../../utils/endpoint_alert_check'; +import { + isAlertFromSentinelOneEvent, + SENTINEL_ONE_AGENT_ID_FIELD, +} from '../../utils/sentinelone_alert_check'; +import { + CROWDSTRIKE_AGENT_ID_FIELD, + isAlertFromCrowdstrikeEvent, +} from '../../utils/crowdstrike_alert_check'; +import { renderHook } from '@testing-library/react-hooks'; +import { useSummaryRows } from './get_alert_summary_rows'; +import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; +import { useIsExperimentalFeatureEnabled } from '../../hooks/use_experimental_features'; + +jest.mock('../../utils/endpoint_alert_check'); +jest.mock('../../utils/sentinelone_alert_check'); +jest.mock('../../utils/crowdstrike_alert_check'); +jest.mock('../../hooks/use_experimental_features', () => ({ + useIsExperimentalFeatureEnabled: jest.fn(), +})); + +describe('useSummaryRows', () => { + const mockData: TimelineEventsDetailsItem[] = [ + { + category: 'event', + field: 'event.category', + originalValue: ['process'], + values: ['process'], + isObjectArray: false, + }, + { + category: 'kibana', + field: 'kibana.alert.rule.uuid', + originalValue: 'rule-uuid', + values: ['rule-uuid'], + isObjectArray: false, + }, + { + category: 'host', + field: 'host.name', + originalValue: 'test-host', + values: ['text-host'], + isObjectArray: false, + }, + ]; + + const mockBrowserFields = {}; + const mockScopeId = 'scope-id'; + const mockEventId = 'event-id'; + const mockInvestigationFields: string[] = []; + + beforeEach(() => { + jest.clearAllMocks(); + (isAlertFromEndpointEvent as jest.Mock).mockReturnValue(true); + (isAlertFromCrowdstrikeEvent as jest.Mock).mockReturnValue(false); + }); + + it('returns summary rows for default event categories', () => { + const { result } = renderHook(() => + useSummaryRows({ + data: mockData, + browserFields: mockBrowserFields, + scopeId: mockScopeId, + eventId: mockEventId, + investigationFields: mockInvestigationFields, + }) + ); + + expect(result.current).toEqual( + expect.arrayContaining([ + expect.objectContaining({ title: 'host.name', description: expect.anything() }), + ]) + ); + }); + + it('excludes fields not related to the event source', () => { + (isAlertFromEndpointEvent as jest.Mock).mockReturnValue(false); + + const { result } = renderHook(() => + useSummaryRows({ + data: mockData, + browserFields: mockBrowserFields, + scopeId: mockScopeId, + eventId: mockEventId, + investigationFields: mockInvestigationFields, + }) + ); + + expect(result.current).not.toEqual( + expect.arrayContaining([ + expect.objectContaining({ + title: 'agent.id', + description: expect.anything(), + }), + ]) + ); + }); + + it('includes sentinel_one agent status field', () => { + (useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue(true); + (isAlertFromSentinelOneEvent as jest.Mock).mockReturnValue(true); + + const sentinelOneData: TimelineEventsDetailsItem[] = [ + ...mockData, + { + category: 'host', + field: SENTINEL_ONE_AGENT_ID_FIELD, + originalValue: 'sentinelone-agent-id', + values: ['sentinelone-agent-id'], + isObjectArray: false, + }, + ]; + + const { result } = renderHook(() => + useSummaryRows({ + data: sentinelOneData, + browserFields: mockBrowserFields, + scopeId: mockScopeId, + eventId: mockEventId, + investigationFields: mockInvestigationFields, + }) + ); + + expect(result.current).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + title: 'Agent status', + description: expect.objectContaining({ values: ['sentinelone-agent-id'] }), + }), + ]) + ); + }); + + it('includes crowdstrike agent status field', () => { + (useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue(true); + (isAlertFromCrowdstrikeEvent as jest.Mock).mockReturnValue(true); + + const crowdstrikeData: TimelineEventsDetailsItem[] = [ + ...mockData, + { + category: 'host', + field: CROWDSTRIKE_AGENT_ID_FIELD, + originalValue: 'crowdstrike-agent-id', + values: ['crowdstrike-agent-id'], + isObjectArray: false, + }, + ]; + + const { result } = renderHook(() => + useSummaryRows({ + data: crowdstrikeData, + browserFields: mockBrowserFields, + scopeId: mockScopeId, + eventId: mockEventId, + investigationFields: mockInvestigationFields, + }) + ); + + expect(result.current).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + title: 'Agent status', + description: expect.objectContaining({ values: ['crowdstrike-agent-id'] }), + }), + ]) + ); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/get_alert_summary_rows.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/get_alert_summary_rows.tsx index 76b6c355cf35c..b079d3575f7c7 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/get_alert_summary_rows.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/get_alert_summary_rows.tsx @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - +import { useMemo } from 'react'; import { find, isEmpty, uniqBy } from 'lodash/fp'; import { ALERT_RULE_PARAMETERS, ALERT_RULE_TYPE } from '@kbn/rule-data-utils'; @@ -38,6 +38,11 @@ import { SENTINEL_ONE_AGENT_ID_FIELD, isAlertFromSentinelOneEvent, } from '../../utils/sentinelone_alert_check'; +import { + CROWDSTRIKE_AGENT_ID_FIELD, + isAlertFromCrowdstrikeEvent, +} from '../../utils/crowdstrike_alert_check'; +import { useIsExperimentalFeatureEnabled } from '../../hooks/use_experimental_features'; const THRESHOLD_TERMS_FIELD = `${ALERT_THRESHOLD_RESULT}.terms.field`; const THRESHOLD_TERMS_VALUE = `${ALERT_THRESHOLD_RESULT}.terms.value`; @@ -55,6 +60,11 @@ const alwaysDisplayedFields: EventSummaryField[] = [ overrideField: AGENT_STATUS_FIELD_NAME, label: i18n.AGENT_STATUS, }, + { + id: CROWDSTRIKE_AGENT_ID_FIELD, + overrideField: AGENT_STATUS_FIELD_NAME, + label: i18n.AGENT_STATUS, + }, // ** // { id: 'user.name' }, { id: 'rule.name' }, @@ -297,7 +307,7 @@ export function getEventCategoriesFromData(data: TimelineEventsDetailsItem[]): E return { primaryEventCategory, allEventCategories }; } -export const getSummaryRows = ({ +export const useSummaryRows = ({ data, browserFields, scopeId, @@ -305,7 +315,6 @@ export const getSummaryRows = ({ isDraggable = false, isReadOnly = false, investigationFields, - sentinelOneManualHostActionsEnabled, }: { data: TimelineEventsDetailsItem[]; browserFields: BrowserFields; @@ -314,97 +323,122 @@ export const getSummaryRows = ({ investigationFields?: string[]; isDraggable?: boolean; isReadOnly?: boolean; - sentinelOneManualHostActionsEnabled?: boolean; }) => { - const eventCategories = getEventCategoriesFromData(data); - - const eventCodeField = find({ category: 'event', field: 'event.code' }, data); - - const eventCode = Array.isArray(eventCodeField?.originalValue) - ? eventCodeField?.originalValue?.[0] - : eventCodeField?.originalValue; - - const eventRuleTypeField = find({ category: 'kibana', field: ALERT_RULE_TYPE }, data); - const eventRuleType = Array.isArray(eventRuleTypeField?.originalValue) - ? eventRuleTypeField?.originalValue?.[0] - : eventRuleTypeField?.originalValue; - - const tableFields = getEventFieldsToDisplay({ - eventCategories, - eventCode, - eventRuleType, - highlightedFieldsOverride: investigationFields ?? [], - }); - - return data != null - ? tableFields.reduce((acc, field) => { - const item = data.find( - (d) => d.field === field.id || (field.legacyId && d.field === field.legacyId) - ); - if (!item || isEmpty(item.values)) { - return acc; - } - - // If we found the data by its legacy id we swap the ids to display the correct one - if (item.field === field.legacyId) { - field.id = field.legacyId; - } - - const linkValueField = - field.linkField != null && data.find((d) => d.field === field.linkField); - const description = { - ...getEnrichedFieldInfo({ - item, - linkValueField: linkValueField || undefined, - contextId: scopeId, - scopeId, - browserFields, - eventId, - field, - }), - isDraggable, - isReadOnly, - }; - - if (field.id === 'agent.id' && !isAlertFromEndpointEvent({ data })) { - return acc; - } - - if ( - field.id === SENTINEL_ONE_AGENT_ID_FIELD && - sentinelOneManualHostActionsEnabled && - !isAlertFromSentinelOneEvent({ data }) - ) { - return acc; - } - - if (field.id === THRESHOLD_TERMS_FIELD) { - const enrichedInfo = enrichThresholdTerms(item, data, description); - if (enrichedInfo) { - return [...acc, ...enrichedInfo]; - } else { + const sentinelOneManualHostActionsEnabled = useIsExperimentalFeatureEnabled( + 'sentinelOneManualHostActionsEnabled' + ); + const crowdstrikeManualHostActionsEnabled = useIsExperimentalFeatureEnabled( + 'responseActionsCrowdstrikeManualHostIsolationEnabled' + ); + return useMemo(() => { + const eventCategories = getEventCategoriesFromData(data); + + const eventCodeField = find({ category: 'event', field: 'event.code' }, data); + + const eventCode = Array.isArray(eventCodeField?.originalValue) + ? eventCodeField?.originalValue?.[0] + : eventCodeField?.originalValue; + + const eventRuleTypeField = find({ category: 'kibana', field: ALERT_RULE_TYPE }, data); + const eventRuleType = Array.isArray(eventRuleTypeField?.originalValue) + ? eventRuleTypeField?.originalValue?.[0] + : eventRuleTypeField?.originalValue; + + const tableFields = getEventFieldsToDisplay({ + eventCategories, + eventCode, + eventRuleType, + highlightedFieldsOverride: investigationFields ?? [], + }); + + return data != null + ? tableFields.reduce((acc, field) => { + const item = data.find( + (d) => d.field === field.id || (field.legacyId && d.field === field.legacyId) + ); + if (!item || isEmpty(item.values)) { + return acc; + } + + // If we found the data by its legacy id we swap the ids to display the correct one + if (item.field === field.legacyId) { + field.id = field.legacyId; + } + + const linkValueField = + field.linkField != null && data.find((d) => d.field === field.linkField); + const description = { + ...getEnrichedFieldInfo({ + item, + linkValueField: linkValueField || undefined, + contextId: scopeId, + scopeId, + browserFields, + eventId, + field, + }), + isDraggable, + isReadOnly, + }; + + if (field.id === 'agent.id' && !isAlertFromEndpointEvent({ data })) { + return acc; + } + + if ( + field.id === SENTINEL_ONE_AGENT_ID_FIELD && + sentinelOneManualHostActionsEnabled && + !isAlertFromSentinelOneEvent({ data }) + ) { return acc; } - } - if (field.id === THRESHOLD_CARDINALITY_FIELD) { - const enrichedInfo = enrichThresholdCardinality(item, data, description); - if (enrichedInfo) { - return [...acc, enrichedInfo]; - } else { + if ( + field.id === CROWDSTRIKE_AGENT_ID_FIELD && + crowdstrikeManualHostActionsEnabled && + !isAlertFromCrowdstrikeEvent({ data }) + ) { return acc; } - } - - return [ - ...acc, - { - title: field.label ?? field.id, - description, - }, - ]; - }, []) - : []; + + if (field.id === THRESHOLD_TERMS_FIELD) { + const enrichedInfo = enrichThresholdTerms(item, data, description); + if (enrichedInfo) { + return [...acc, ...enrichedInfo]; + } else { + return acc; + } + } + + if (field.id === THRESHOLD_CARDINALITY_FIELD) { + const enrichedInfo = enrichThresholdCardinality(item, data, description); + if (enrichedInfo) { + return [...acc, enrichedInfo]; + } else { + return acc; + } + } + + return [ + ...acc, + { + title: field.label ?? field.id, + description, + }, + ]; + }, []) + : []; + }, [ + browserFields, + data, + eventId, + isDraggable, + scopeId, + isReadOnly, + investigationFields, + sentinelOneManualHostActionsEnabled, + crowdstrikeManualHostActionsEnabled, + ]); }; /** diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/helpers.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/helpers.tsx index bac8587eaf2e2..dccea29321671 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/helpers.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/helpers.tsx @@ -24,6 +24,7 @@ import { QUARANTINED_PATH_FIELD_NAME, } from '../../../timelines/components/timeline/body/renderers/constants'; import { SENTINEL_ONE_AGENT_ID_FIELD } from '../../utils/sentinelone_alert_check'; +import { CROWDSTRIKE_AGENT_ID_FIELD } from '../../utils/crowdstrike_alert_check'; /** * Defines the behavior of the search input that appears above the table of data @@ -183,6 +184,7 @@ export const FIELDS_WITHOUT_ACTIONS: { [field: string]: boolean } = { [AGENT_STATUS_FIELD_NAME]: true, [QUARANTINED_PATH_FIELD_NAME]: true, [SENTINEL_ONE_AGENT_ID_FIELD]: true, + [CROWDSTRIKE_AGENT_ID_FIELD]: true, }; /** diff --git a/x-pack/plugins/security_solution/public/common/components/navigation/tab_navigation/tab_navigation.test.tsx b/x-pack/plugins/security_solution/public/common/components/navigation/tab_navigation/tab_navigation.test.tsx index f5bc002ac507d..45d4d9fbbbefd 100644 --- a/x-pack/plugins/security_solution/public/common/components/navigation/tab_navigation/tab_navigation.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/navigation/tab_navigation/tab_navigation.test.tsx @@ -41,14 +41,12 @@ const hostName = 'siem-window'; describe('Table Navigation', () => { const mockHasMlUserPermissions = true; - const mockRiskyHostEnabled = true; mockUseRouteSpy.mockReturnValue([{ tabName: HostsTableType.authentications }]); const mockProps: TabNavigationProps = { navTabs: navTabsHostDetails({ hostName, hasMlUserPermissions: mockHasMlUserPermissions, - isRiskyHostsEnabled: mockRiskyHostEnabled, }), }; diff --git a/x-pack/plugins/security_solution/public/common/hooks/timeline/use_init_timeline_url_param.ts b/x-pack/plugins/security_solution/public/common/hooks/timeline/use_init_timeline_url_param.ts index bb3c595ee3d9d..5f40cfd196889 100644 --- a/x-pack/plugins/security_solution/public/common/hooks/timeline/use_init_timeline_url_param.ts +++ b/x-pack/plugins/security_solution/public/common/hooks/timeline/use_init_timeline_url_param.ts @@ -7,11 +7,14 @@ import { useCallback, useEffect } from 'react'; import { safeDecode } from '@kbn/rison'; +import { useSelector } from 'react-redux'; -import { TimelineTabs } from '../../../../common/types'; +import type { State } from '../../store'; +import { TimelineId, TimelineTabs } from '../../../../common/types'; import { useInitializeUrlParam } from '../../utils/global_query_string'; import { useQueryTimelineById } from '../../../timelines/components/open_timeline/helpers'; -import type { TimelineUrl } from '../../../timelines/store/model'; +import type { TimelineModel, TimelineUrl } from '../../../timelines/store/model'; +import { selectTimelineById } from '../../../timelines/store/selectors'; import { URL_PARAM_KEY } from '../use_url_state'; import { useIsExperimentalFeatureEnabled } from '../use_experimental_features'; @@ -23,6 +26,9 @@ export const useInitTimelineFromUrlParam = () => { const isEsqlTabDisabled = useIsExperimentalFeatureEnabled('timelineEsqlTabDisabled'); const queryTimelineById = useQueryTimelineById(); + const activeTimeline = useSelector((state: State) => + selectTimelineById(state, TimelineId.active) + ); const onInitialize = useCallback( (initialState: TimelineUrl | null) => { @@ -54,13 +60,30 @@ export const useInitTimelineFromUrlParam = () => { const parsedState = safeDecode(timelineState) as TimelineUrl | null; - onInitialize(parsedState); + // Make sure we only re-initialize the timeline if there are siginificant changes to the active timeline. + // Without this check, we could potentially overwrite the timeline. + if (!hasTimelineStateChanged(activeTimeline, parsedState)) { + onInitialize(parsedState); + } }; // This is needed to initialize the timeline from the URL when the user clicks the back / forward buttons window.addEventListener('popstate', listener); return () => window.removeEventListener('popstate', listener); - }, [onInitialize]); + }, [onInitialize, activeTimeline]); useInitializeUrlParam(URL_PARAM_KEY.timeline, onInitialize); }; + +function hasTimelineStateChanged( + activeTimeline: TimelineModel | null, + newState: TimelineUrl | null +) { + return ( + activeTimeline && + newState && + (activeTimeline.id !== newState.id || + activeTimeline.savedSearchId !== newState.savedSearchId || + activeTimeline.graphEventId !== newState.graphEventId) + ); +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/utils/helpers.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/utils/helpers.test.tsx index 8c2bb6bb20dcc..c3b288cb15c79 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/utils/helpers.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/utils/helpers.test.tsx @@ -1805,6 +1805,11 @@ describe('Exception helpers', () => { overrideField: 'agent.status', label: 'Agent status', }, + { + id: 'crowdstrike.event.DeviceId', + overrideField: 'agent.status', + label: 'Agent status', + }, { id: 'user.name', }, diff --git a/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/responder_action_button.tsx b/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/responder_action_button.tsx index 6701d6e5cb36a..cb5876f27dd67 100644 --- a/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/responder_action_button.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/responder_action_button.tsx @@ -15,8 +15,9 @@ import { import { useUserPrivileges } from '../../../common/components/user_privileges'; export const ResponderActionButton = memo( - ({ endpointId, onClick }) => { + ({ agentType, endpointId, onClick }) => { const { handleResponseActionsClick, isDisabled, tooltip } = useResponderActionData({ + agentType, endpointId, onClick, }); diff --git a/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_data.test.ts b/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_data.test.ts index e6b3b1886deec..9a00f462cd870 100644 --- a/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_data.test.ts +++ b/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_data.test.ts @@ -11,6 +11,7 @@ import { renderHook } from '@testing-library/react-hooks'; import { useGetEndpointDetails } from '../../../management/hooks'; import { HostStatus } from '../../../../common/endpoint/types'; import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; +import { HOST_ENDPOINT_UNENROLLED_TOOLTIP } from './translations'; jest.mock('../../../common/hooks/use_experimental_features'); jest.mock('../../../management/hooks', () => ({ @@ -110,6 +111,17 @@ describe('#useResponderActionData', () => { ); expect(result.current.isDisabled).toEqual(true); }); + + it('should return responder menu item `disabled` when agentType is `endpoint` but no endpoint id is provided', () => { + const { result } = renderHook(() => + useResponderActionData({ + endpointId: '', + agentType: 'endpoint', + }) + ); + expect(result.current.isDisabled).toEqual(true); + expect(result.current.tooltip).toEqual(HOST_ENDPOINT_UNENROLLED_TOOLTIP); + }); }); describe('when agentType is `sentinel_one`', () => { diff --git a/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_data.ts b/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_data.ts index 820837393461a..b5e068ed4dbde 100644 --- a/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_data.ts +++ b/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_data.ts @@ -29,7 +29,7 @@ import { getFieldValue } from '../host_isolation/helpers'; export interface ResponderContextMenuItemProps { endpointId: string; onClick?: () => void; - agentType?: ResponseActionAgentType; + agentType: ResponseActionAgentType; eventData?: TimelineEventsDetailsItem[] | null; } @@ -72,7 +72,7 @@ const getThirdPartyAgentInfo = ( export const useResponderActionData = ({ endpointId, onClick, - agentType = 'endpoint', + agentType, eventData, }: ResponderContextMenuItemProps): { handleResponseActionsClick: () => void; @@ -112,6 +112,10 @@ export const useResponderActionData = ({ } } + if (!endpointId) { + return [true, HOST_ENDPOINT_UNENROLLED_TOOLTIP]; + } + // Still loading host info if (isFetching) { return [true, LOADING_ENDPOINT_DATA_TOOLTIP]; @@ -141,6 +145,7 @@ export const useResponderActionData = ({ return [false, undefined]; }, [ isEndpointHost, + endpointId, isFetching, error, hostInfo?.host_status, @@ -160,10 +165,10 @@ export const useResponderActionData = ({ platform: agentInfoFromAlert.host.os.family, }); } - if (hostInfo) { + if (isEndpointHost && hostInfo) { showResponseActionsConsole({ agentId: hostInfo.metadata.agent.id, - agentType: 'endpoint', + agentType, capabilities: (hostInfo.metadata.Endpoint.capabilities as EndpointCapabilities[]) ?? [], hostName: hostInfo.metadata.host.name, platform: hostInfo.metadata.host.os.name.toLowerCase() as Platform, diff --git a/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_item.test.tsx b/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_item.test.tsx new file mode 100644 index 0000000000000..750a627985192 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_item.test.tsx @@ -0,0 +1,144 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { useResponderActionItem } from './use_responder_action_item'; +import { useUserPrivileges } from '../../../common/components/user_privileges'; +import { isTimelineEventItemAnAlert } from '../../../common/utils/endpoint_alert_check'; +import { getFieldValue } from '../host_isolation/helpers'; +import { isAlertFromCrowdstrikeEvent } from '../../../common/utils/crowdstrike_alert_check'; +import { isAlertFromSentinelOneEvent } from '../../../common/utils/sentinelone_alert_check'; +import { useResponderActionData } from './use_responder_action_data'; + +jest.mock('../../../common/components/user_privileges'); +jest.mock('../../../common/utils/endpoint_alert_check'); +jest.mock('../host_isolation/helpers'); +jest.mock('../../../common/utils/crowdstrike_alert_check'); +jest.mock('../../../common/utils/sentinelone_alert_check'); +jest.mock('./use_responder_action_data'); + +describe('useResponderActionItem', () => { + const mockUseUserPrivileges = useUserPrivileges as jest.Mock; + const mockIsTimelineEventItemAnAlert = isTimelineEventItemAnAlert as jest.Mock; + const mockGetFieldValue = getFieldValue as jest.Mock; + const mockIsAlertFromCrowdstrikeEvent = isAlertFromCrowdstrikeEvent as jest.Mock; + const mockIsAlertFromSentinelOneEvent = isAlertFromSentinelOneEvent as jest.Mock; + const mockUseResponderActionData = useResponderActionData as jest.Mock; + + beforeEach(() => { + jest.clearAllMocks(); + mockUseResponderActionData.mockImplementation(() => ({ + handleResponseActionsClick: jest.fn(), + isDisabled: false, + tooltip: 'Tooltip text', + })); + }); + + it('should return an empty array if user privileges are loading', () => { + mockUseUserPrivileges.mockReturnValue({ + endpointPrivileges: { + loading: true, + canAccessResponseConsole: false, + }, + }); + + const { result } = renderHook(() => useResponderActionItem(null, jest.fn())); + expect(result.current).toEqual([]); + }); + + it('should return an empty array if user cannot access response console', () => { + mockUseUserPrivileges.mockReturnValue({ + endpointPrivileges: { + loading: false, + canAccessResponseConsole: false, + }, + }); + + const { result } = renderHook(() => useResponderActionItem(null, jest.fn())); + expect(result.current).toEqual([]); + }); + + it('should return an empty array if the event is not an alert', () => { + mockUseUserPrivileges.mockReturnValue({ + endpointPrivileges: { + loading: false, + canAccessResponseConsole: true, + }, + }); + mockIsTimelineEventItemAnAlert.mockReturnValue(false); + + const { result } = renderHook(() => useResponderActionItem(null, jest.fn())); + expect(result.current).toEqual([]); + }); + + it('should return the response action item if all conditions are met for a generic endpoint', () => { + mockUseUserPrivileges.mockReturnValue({ + endpointPrivileges: { + loading: false, + canAccessResponseConsole: true, + }, + }); + mockIsTimelineEventItemAnAlert.mockReturnValue(true); + mockGetFieldValue.mockReturnValue('endpoint-id'); + mockIsAlertFromCrowdstrikeEvent.mockReturnValue(false); + mockIsAlertFromSentinelOneEvent.mockReturnValue(false); + + renderHook(() => useResponderActionItem([], jest.fn())); + + expect(mockUseResponderActionData).toHaveBeenCalledWith({ + agentType: 'endpoint', + endpointId: 'endpoint-id', + eventData: null, + onClick: expect.any(Function), + }); + }); + + it('should return the response action item if all conditions are met for a Crowdstrike event', () => { + mockUseUserPrivileges.mockReturnValue({ + endpointPrivileges: { + loading: false, + canAccessResponseConsole: true, + }, + }); + mockIsTimelineEventItemAnAlert.mockReturnValue(true); + mockGetFieldValue.mockReturnValue('crowdstrike-id'); + mockIsAlertFromCrowdstrikeEvent.mockReturnValue(true); + mockIsAlertFromSentinelOneEvent.mockReturnValue(false); + + renderHook(() => useResponderActionItem([], jest.fn())); + + expect(mockUseResponderActionData).toHaveBeenCalledWith({ + agentType: 'crowdstrike', + endpointId: 'crowdstrike-id', + eventData: [], + onClick: expect.any(Function), + }); + }); + + it('should return the response action item if all conditions are met for a SentinelOne event', () => { + mockUseUserPrivileges.mockReturnValue({ + endpointPrivileges: { + loading: false, + canAccessResponseConsole: true, + }, + }); + + mockIsTimelineEventItemAnAlert.mockReturnValue(true); + mockGetFieldValue.mockReturnValue('sentinelone-id'); + mockIsAlertFromCrowdstrikeEvent.mockReturnValue(false); + mockIsAlertFromSentinelOneEvent.mockReturnValue(true); + + renderHook(() => useResponderActionItem([], jest.fn())); + + expect(mockUseResponderActionData).toHaveBeenCalledWith({ + agentType: 'sentinel_one', + endpointId: 'sentinelone-id', + eventData: [], + onClick: expect.any(Function), + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_item.tsx b/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_item.tsx index 41fad6fd2e174..57b51c23f2032 100644 --- a/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_item.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/use_responder_action_item.tsx @@ -8,6 +8,7 @@ import React, { useMemo } from 'react'; import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; import { FormattedMessage } from '@kbn/i18n-react'; +import { isAlertFromCrowdstrikeEvent } from '../../../common/utils/crowdstrike_alert_check'; import { isAlertFromSentinelOneEvent } from '../../../common/utils/sentinelone_alert_check'; import type { ResponseActionAgentType } from '../../../../common/endpoint/service/response_actions/constants'; import { useUserPrivileges } from '../../../common/components/user_privileges'; @@ -32,15 +33,20 @@ export const useResponderActionItem = ( [eventDetailsData] ); - const agentType: ResponseActionAgentType = useMemo( - () => - eventDetailsData - ? isAlertFromSentinelOneEvent({ data: eventDetailsData }) - ? 'sentinel_one' - : 'endpoint' - : 'endpoint', - [eventDetailsData] - ); + const agentType: ResponseActionAgentType = useMemo(() => { + if (!eventDetailsData) { + return 'endpoint'; + } + + if (isAlertFromSentinelOneEvent({ data: eventDetailsData })) { + return 'sentinel_one'; + } + if (isAlertFromCrowdstrikeEvent({ data: eventDetailsData })) { + return 'crowdstrike'; + } + + return 'endpoint'; + }, [eventDetailsData]); const { handleResponseActionsClick, isDisabled, tooltip } = useResponderActionData({ endpointId, diff --git a/x-pack/plugins/security_solution/public/detections/components/host_isolation/index.tsx b/x-pack/plugins/security_solution/public/detections/components/host_isolation/index.tsx index cd9fcee2a353f..6804ec9fcfc93 100644 --- a/x-pack/plugins/security_solution/public/detections/components/host_isolation/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/host_isolation/index.tsx @@ -33,9 +33,7 @@ export const HostIsolationPanel = React.memo( ); const sentinelOneAgentId = useMemo(() => getSentinelOneAgentId(details), [details]); - const crowdstrikeAgentId = useMemo(() => { - return getCrowdstrikeAgentId(details); - }, [details]); + const crowdstrikeAgentId = useMemo(() => getCrowdstrikeAgentId(details), [details]); const hostName = useMemo( () => getFieldValue({ category: 'host', field: 'host.name' }, details), diff --git a/x-pack/plugins/security_solution/public/detections/components/host_isolation/use_host_isolation_action.test.tsx b/x-pack/plugins/security_solution/public/detections/components/host_isolation/use_host_isolation_action.test.tsx index f263d80ea92dd..5adbbe58de167 100644 --- a/x-pack/plugins/security_solution/public/detections/components/host_isolation/use_host_isolation_action.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/host_isolation/use_host_isolation_action.test.tsx @@ -16,17 +16,16 @@ import { useGetSentinelOneAgentStatus, } from '../../../management/hooks/agents/use_get_agent_status'; import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; +import type { ResponseActionAgentType } from '../../../../common/endpoint/service/response_actions/constants'; jest.mock('../../../management/hooks/agents/use_get_agent_status'); jest.mock('../../../common/hooks/use_experimental_features'); -type AgentType = 'endpoint' | 'sentinel_one' | 'crowdstrike'; const useIsExperimentalFeatureEnabledMock = useIsExperimentalFeatureEnabled as jest.Mock; const useGetSentinelOneAgentStatusMock = useGetSentinelOneAgentStatus as jest.Mock; const useGetAgentStatusMock = useGetAgentStatus as jest.Mock; const useAgentStatusHookMock = useAgentStatusHook as jest.Mock; -// TODO TC: change crowdstrike tests when the useAgentStatus is implemented for Crowdstrike - now it defaults to `sentinel_one` describe('useHostIsolationAction', () => { describe.each([ ['useGetSentinelOneAgentStatus', useGetSentinelOneAgentStatusMock], @@ -40,7 +39,7 @@ describe('useHostIsolationAction', () => { return wrapper; }; - const render = (agentTypeAlert: AgentType) => + const render = (agentTypeAlert: ResponseActionAgentType) => renderHook( () => useHostIsolationAction({ @@ -48,6 +47,13 @@ describe('useHostIsolationAction', () => { detailsData: agentTypeAlert === 'sentinel_one' ? [ + { + category: 'kibana', + field: 'kibana.alert.rule.uuid', + isObjectArray: false, + values: ['ruleId'], + originalValue: ['ruleId'], + }, { category: 'event', field: 'event.module', @@ -65,6 +71,13 @@ describe('useHostIsolationAction', () => { ] : agentTypeAlert === 'crowdstrike' ? [ + { + category: 'kibana', + field: 'kibana.alert.rule.uuid', + isObjectArray: false, + values: ['ruleId'], + originalValue: ['ruleId'], + }, { category: 'event', field: 'event.module', @@ -116,8 +129,8 @@ describe('useHostIsolationAction', () => { it(`${name} is invoked as 'enabled' when Crowdstrike alert and FF enabled`, () => { render('crowdstrike'); - expect(hook).toHaveBeenCalledWith([''], 'sentinel_one', { - enabled: false, + expect(hook).toHaveBeenCalledWith(['expectedCrowdstrikeAgentId'], 'crowdstrike', { + enabled: true, }); }); @@ -134,7 +147,7 @@ describe('useHostIsolationAction', () => { useIsExperimentalFeatureEnabledMock.mockReturnValue(false); render('crowdstrike'); - expect(hook).toHaveBeenCalledWith([''], 'sentinel_one', { + expect(hook).toHaveBeenCalledWith(['expectedCrowdstrikeAgentId'], 'crowdstrike', { enabled: false, }); }); @@ -142,7 +155,7 @@ describe('useHostIsolationAction', () => { it(`${name} is invoked as 'disabled' when endpoint alert`, () => { render('endpoint'); - expect(hook).toHaveBeenCalledWith([''], 'sentinel_one', { + expect(hook).toHaveBeenCalledWith([''], 'endpoint', { enabled: false, }); }); diff --git a/x-pack/plugins/security_solution/public/detections/components/host_isolation/use_host_isolation_action.tsx b/x-pack/plugins/security_solution/public/detections/components/host_isolation/use_host_isolation_action.tsx index 8b054ec811a90..abafc59bef195 100644 --- a/x-pack/plugins/security_solution/public/detections/components/host_isolation/use_host_isolation_action.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/host_isolation/use_host_isolation_action.tsx @@ -77,6 +77,7 @@ export const useHostIsolationAction = ({ const sentinelOneAgentId = useMemo(() => getSentinelOneAgentId(detailsData), [detailsData]); const crowdstrikeAgentId = useMemo(() => getCrowdstrikeAgentId(detailsData), [detailsData]); + const externalAgentId = sentinelOneAgentId ?? crowdstrikeAgentId ?? ''; const hostOsFamily = useMemo( () => getFieldValue({ category: 'host', field: 'host.os.name' }, detailsData), [detailsData] @@ -87,6 +88,16 @@ export const useHostIsolationAction = ({ [detailsData] ); + const agentType = useMemo(() => { + if (isSentinelOneAlert) { + return 'sentinel_one'; + } + if (isCrowdstrikeAlert) { + return 'crowdstrike'; + } + return 'endpoint'; + }, [isCrowdstrikeAlert, isSentinelOneAlert]); + const { loading: loadingHostIsolationStatus, isIsolated, @@ -94,26 +105,23 @@ export const useHostIsolationAction = ({ capabilities, } = useEndpointHostIsolationStatus({ agentId, - agentType: sentinelOneAgentId ? 'sentinel_one' : 'endpoint', + agentType, }); - const { data: sentinelOneAgentData } = useAgentStatus( - [sentinelOneAgentId || ''], - 'sentinel_one', - { - enabled: !!sentinelOneAgentId && sentinelOneManualHostActionsEnabled, - } - ); - const sentinelOneAgentStatus = sentinelOneAgentData?.[`${sentinelOneAgentId}`]; - // TODO TC: Add support for Crowdstrike agent status - ongoing work by Ash :+1: + const { data: externalAgentData } = useAgentStatus([externalAgentId], agentType, { + enabled: + (!!sentinelOneAgentId && sentinelOneManualHostActionsEnabled) || + (!!crowdstrikeAgentId && crowdstrikeManualHostActionsEnabled), + }); + + const externalAgentStatus = externalAgentData?.[externalAgentId]; const isHostIsolated = useMemo(() => { - if (sentinelOneManualHostActionsEnabled && isSentinelOneAlert) { - return sentinelOneAgentStatus?.isolated; - } - if (crowdstrikeManualHostActionsEnabled && isCrowdstrikeAlert) { - return false; - // return crowdstrikeAgentStatus?.isolated; + if ( + (sentinelOneManualHostActionsEnabled && isSentinelOneAlert) || + (crowdstrikeManualHostActionsEnabled && isCrowdstrikeAlert) + ) { + return externalAgentStatus?.isolated; } return isIsolated; @@ -121,7 +129,7 @@ export const useHostIsolationAction = ({ isIsolated, isSentinelOneAlert, isCrowdstrikeAlert, - sentinelOneAgentStatus?.isolated, + externalAgentStatus?.isolated, sentinelOneManualHostActionsEnabled, crowdstrikeManualHostActionsEnabled, ]); @@ -135,18 +143,24 @@ export const useHostIsolationAction = ({ }); } - if (sentinelOneManualHostActionsEnabled && isSentinelOneAlert && sentinelOneAgentStatus) { - return sentinelOneAgentStatus.status === 'healthy'; + if ( + (externalAgentStatus && sentinelOneManualHostActionsEnabled && isSentinelOneAlert) || + (externalAgentStatus && crowdstrikeManualHostActionsEnabled && isCrowdstrikeAlert) + ) { + return externalAgentStatus.status === 'healthy'; } + return false; }, [ - agentVersion, - capabilities, - hostOsFamily, isEndpointAlert, - isSentinelOneAlert, - sentinelOneAgentStatus, sentinelOneManualHostActionsEnabled, + isSentinelOneAlert, + externalAgentStatus, + crowdstrikeManualHostActionsEnabled, + isCrowdstrikeAlert, + hostOsFamily, + agentVersion, + capabilities, ]); const isolateHostHandler = useCallback(() => { @@ -159,34 +173,31 @@ export const useHostIsolationAction = ({ }, [closePopover, isHostIsolated, onAddIsolationStatusClick]); const isIsolationActionDisabled = useMemo(() => { - if (sentinelOneManualHostActionsEnabled && isSentinelOneAlert) { + if ( + (sentinelOneManualHostActionsEnabled && isSentinelOneAlert) || + (crowdstrikeManualHostActionsEnabled && isCrowdstrikeAlert) + ) { // 8.15 use FF for computing if action is enabled if (agentStatusClientEnabled) { - return sentinelOneAgentStatus?.status === HostStatus.UNENROLLED; + return externalAgentStatus?.status === HostStatus.UNENROLLED; } // else use the old way - if (!sentinelOneAgentStatus) { + if (!externalAgentStatus) { return true; } - const { isUninstalled, isPendingUninstall } = - sentinelOneAgentStatus as AgentStatusInfo[string]; + const { isUninstalled, isPendingUninstall } = externalAgentStatus as AgentStatusInfo[string]; return isUninstalled || isPendingUninstall; } - if (crowdstrikeManualHostActionsEnabled && isCrowdstrikeAlert) { - // TODO TC: crowdstrikeAgentStatus functionality is going to be implemented in another PR - return false; - } - return agentStatus === HostStatus.UNENROLLED; }, [ agentStatus, agentStatusClientEnabled, isSentinelOneAlert, - sentinelOneAgentStatus, + externalAgentStatus, sentinelOneManualHostActionsEnabled, crowdstrikeManualHostActionsEnabled, isCrowdstrikeAlert, @@ -214,7 +225,7 @@ export const useHostIsolationAction = ({ isSentinelOneAlert && sentinelOneManualHostActionsEnabled && sentinelOneAgentId && - sentinelOneAgentStatus && + externalAgentStatus && hasActionsAllPrivileges ) { return menuItems; @@ -224,7 +235,7 @@ export const useHostIsolationAction = ({ isCrowdstrikeAlert && crowdstrikeManualHostActionsEnabled && crowdstrikeAgentId && - // status && + externalAgentStatus && hasActionsAllPrivileges ) { return menuItems; @@ -251,7 +262,7 @@ export const useHostIsolationAction = ({ isSentinelOneAlert, loadingHostIsolationStatus, menuItems, - sentinelOneAgentStatus, + externalAgentStatus, sentinelOneAgentId, sentinelOneManualHostActionsEnabled, crowdstrikeAgentId, diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/risk_details_tab_body/index.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/risk_details_tab_body/index.tsx index 2edd3211a225f..b9cfcd18b6cfd 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/risk_details_tab_body/index.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/risk_details_tab_body/index.tsx @@ -9,6 +9,7 @@ import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiPanel } from '@elastic/eui'; import React, { useCallback, useMemo } from 'react'; import styled from 'styled-components'; +import { useUpsellingComponent } from '../../../common/hooks/use_upselling'; import { RISKY_HOSTS_DASHBOARD_TITLE, RISKY_USERS_DASHBOARD_TITLE } from '../risk_score/constants'; import { EnableRiskScore } from '../enable_risk_score'; import { useDeepEqualSelector } from '../../../common/hooks/use_selector'; @@ -130,6 +131,11 @@ const RiskDetailsTabBodyComponent: React.FC< const privileges = useMissingRiskEnginePrivileges(); + const RiskScoreUpsell = useUpsellingComponent('entity_analytics_panel'); + if (RiskScoreUpsell) { + return ; + } + if (!privileges.isLoading && !privileges.hasAllRequiredPrivileges) { return ( diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/user_risk_score_tab_body.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/user_risk_score_tab_body.tsx index 3d0b6bf2e334f..de17151fb68b7 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/user_risk_score_tab_body.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/user_risk_score_tab_body.tsx @@ -26,6 +26,7 @@ import { useRiskEngineStatus } from '../api/hooks/use_risk_engine_status'; import { RiskScoreUpdatePanel } from './risk_score_update_panel'; import { useMissingRiskEnginePrivileges } from '../hooks/use_missing_risk_engine_privileges'; import { RiskEnginePrivilegesCallOut } from './risk_engine_privileges_callout'; +import { useUpsellingComponent } from '../../common/hooks/use_upselling'; const UserRiskScoreTableManage = manageQuery(UserRiskScoreTable); @@ -97,6 +98,11 @@ export const UserRiskScoreQueryTabBody = ({ isDeprecated: isDeprecated && !loading, }; + const RiskScoreUpsell = useUpsellingComponent('entity_analytics_panel'); + if (RiskScoreUpsell) { + return ; + } + if (!privileges.isLoading && !privileges.hasAllRequiredPrivileges) { return ( diff --git a/x-pack/plugins/security_solution/public/explore/hosts/pages/details/index.tsx b/x-pack/plugins/security_solution/public/explore/hosts/pages/details/index.tsx index dda6437ba783d..c5a0e84e67097 100644 --- a/x-pack/plugins/security_solution/public/explore/hosts/pages/details/index.tsx +++ b/x-pack/plugins/security_solution/public/explore/hosts/pages/details/index.tsx @@ -19,7 +19,7 @@ import { useDispatch } from 'react-redux'; import type { Filter } from '@kbn/es-query'; import { buildEsQuery } from '@kbn/es-query'; import { getEsQueryConfig } from '@kbn/data-plugin/common'; -import { tableDefaults, dataTableSelectors, TableId } from '@kbn/securitysolution-data-table'; +import { dataTableSelectors, tableDefaults, TableId } from '@kbn/securitysolution-data-table'; import { useCalculateEntityRiskScore } from '../../../../entity_analytics/api/hooks/use_calculate_entity_risk_score'; import { useAssetCriticalityData, @@ -46,8 +46,8 @@ import { useMlCapabilities } from '../../../../common/components/ml/hooks/use_ml import { scoreIntervalToDateTime } from '../../../../common/components/ml/score/score_interval_to_datetime'; import { TabNavigation } from '../../../../common/components/navigation/tab_navigation'; import { - HostOverview, HOST_OVERVIEW_RISK_SCORE_QUERY_ID, + HostOverview, } from '../../../../overview/components/host_overview'; import { SiemSearchBar } from '../../../../common/components/search_bar'; import { SecuritySolutionPageWrapper } from '../../../../common/components/page_wrapper'; @@ -78,7 +78,6 @@ import { EmptyPrompt } from '../../../../common/components/empty_prompt'; import { AlertCountByRuleByStatus } from '../../../../common/components/alert_count_by_status'; import { useLicense } from '../../../../common/hooks/use_license'; import { ResponderActionButton } from '../../../../detections/components/endpoint_responder/responder_action_button'; -import { useHasSecurityCapability } from '../../../../helper_hooks'; import { useRefetchOverviewPageRiskScore } from '../../../../entity_analytics/api/hooks/use_refetch_overview_page_risk_score'; const ES_HOST_FIELD = 'host.name'; @@ -167,8 +166,6 @@ const HostDetailsComponent: React.FC = ({ detailName, hostDeta dispatch(setHostDetailsTablesActivePageToZero()); }, [dispatch, detailName]); - const hasEntityAnalyticsCapability = useHasSecurityCapability('entity-analytics'); - const { hasKibanaREAD, hasIndexRead } = useAlertsPrivileges(); const canReadAlerts = hasKibanaREAD && hasIndexRead; @@ -230,6 +227,7 @@ const HostDetailsComponent: React.FC = ({ detailName, hostDeta hostOverview.endpoint?.hostInfo?.metadata.elastic.agent.id && ( ), ]} @@ -296,7 +294,6 @@ const HostDetailsComponent: React.FC = ({ detailName, hostDeta { test('it should skip anomalies tab if without mlUserPermission', () => { const tabs = navTabsHostDetails({ hasMlUserPermissions: false, - isRiskyHostsEnabled: false, hostName: mockHostName, }); expect(tabs).toHaveProperty(HostsTableType.authentications); expect(tabs).toHaveProperty(HostsTableType.uncommonProcesses); expect(tabs).not.toHaveProperty(HostsTableType.anomalies); expect(tabs).toHaveProperty(HostsTableType.events); - expect(tabs).not.toHaveProperty(HostsTableType.risk); + expect(tabs).toHaveProperty(HostsTableType.risk); }); test('it should display anomalies tab if with mlUserPermission', () => { const tabs = navTabsHostDetails({ hasMlUserPermissions: true, - isRiskyHostsEnabled: false, hostName: mockHostName, }); @@ -35,27 +33,12 @@ describe('navTabsHostDetails', () => { expect(tabs).toHaveProperty(HostsTableType.uncommonProcesses); expect(tabs).toHaveProperty(HostsTableType.anomalies); expect(tabs).toHaveProperty(HostsTableType.events); - expect(tabs).not.toHaveProperty(HostsTableType.risk); - }); - - test('it should display risky hosts tab if when risky hosts is enabled', () => { - const tabs = navTabsHostDetails({ - hasMlUserPermissions: false, - isRiskyHostsEnabled: true, - hostName: mockHostName, - }); - - expect(tabs).toHaveProperty(HostsTableType.authentications); - expect(tabs).toHaveProperty(HostsTableType.uncommonProcesses); - expect(tabs).not.toHaveProperty(HostsTableType.anomalies); - expect(tabs).toHaveProperty(HostsTableType.events); expect(tabs).toHaveProperty(HostsTableType.risk); }); test('it should display sessions tab when users are on Enterprise and above license', () => { const tabs = navTabsHostDetails({ hasMlUserPermissions: false, - isRiskyHostsEnabled: true, hostName: mockHostName, isEnterprise: true, }); @@ -70,7 +53,6 @@ describe('navTabsHostDetails', () => { test('it should not display sessions tab when users are not on Enterprise and above license', () => { const tabs = navTabsHostDetails({ hasMlUserPermissions: false, - isRiskyHostsEnabled: true, hostName: mockHostName, isEnterprise: false, }); diff --git a/x-pack/plugins/security_solution/public/explore/hosts/pages/details/nav_tabs.tsx b/x-pack/plugins/security_solution/public/explore/hosts/pages/details/nav_tabs.tsx index ba48f9d3f757c..4f22bf46fa2b8 100644 --- a/x-pack/plugins/security_solution/public/explore/hosts/pages/details/nav_tabs.tsx +++ b/x-pack/plugins/security_solution/public/explore/hosts/pages/details/nav_tabs.tsx @@ -16,13 +16,11 @@ const getTabsOnHostDetailsUrl = (hostName: string, tabName: HostsTableType) => export const navTabsHostDetails = ({ hasMlUserPermissions, - isRiskyHostsEnabled, hostName, isEnterprise, }: { hostName: string; hasMlUserPermissions: boolean; - isRiskyHostsEnabled: boolean; isEnterprise?: boolean; }): HostDetailsNavTab => { const hiddenTabs = []; @@ -71,10 +69,6 @@ export const navTabsHostDetails = ({ hiddenTabs.push(HostsTableType.anomalies); } - if (!isRiskyHostsEnabled) { - hiddenTabs.push(HostsTableType.risk); - } - if (!isEnterprise) { hiddenTabs.push(HostsTableType.sessions); } diff --git a/x-pack/plugins/security_solution/public/explore/hosts/pages/hosts.tsx b/x-pack/plugins/security_solution/public/explore/hosts/pages/hosts.tsx index 81165ddc9a545..450f2532d3244 100644 --- a/x-pack/plugins/security_solution/public/explore/hosts/pages/hosts.tsx +++ b/x-pack/plugins/security_solution/public/explore/hosts/pages/hosts.tsx @@ -53,7 +53,6 @@ import { ID } from '../containers/hosts'; import { EmptyPrompt } from '../../../common/components/empty_prompt'; import { fieldNameExistsFilter } from '../../../common/components/visualization_actions/utils'; import { useLicense } from '../../../common/hooks/use_license'; -import { useHasSecurityCapability } from '../../../helper_hooks'; /** * Need a 100% height here to account for the graph/analyze tool, which sets no explicit height parameters, but fills the available space. @@ -138,7 +137,6 @@ const HostsComponent = () => { }); const isEnterprisePlus = useLicense().isEnterprise(); - const hasEntityAnalyticsCapability = useHasSecurityCapability('entity-analytics'); const onSkipFocusBeforeEventsTable = useCallback(() => { containerElement.current @@ -190,7 +188,6 @@ const HostsComponent = () => { diff --git a/x-pack/plugins/security_solution/public/explore/hosts/pages/nav_tabs.test.tsx b/x-pack/plugins/security_solution/public/explore/hosts/pages/nav_tabs.test.tsx index c2228d3ced11b..23a5834c87188 100644 --- a/x-pack/plugins/security_solution/public/explore/hosts/pages/nav_tabs.test.tsx +++ b/x-pack/plugins/security_solution/public/explore/hosts/pages/nav_tabs.test.tsx @@ -12,7 +12,6 @@ describe('navTabsHosts', () => { test('it should skip anomalies tab if without mlUserPermission', () => { const tabs = navTabsHosts({ hasMlUserPermissions: false, - isRiskyHostsEnabled: false, }); expect(tabs).toHaveProperty(HostsTableType.hosts); expect(tabs).toHaveProperty(HostsTableType.uncommonProcesses); @@ -23,7 +22,6 @@ describe('navTabsHosts', () => { test('it should display anomalies tab if with mlUserPermission', () => { const tabs = navTabsHosts({ hasMlUserPermissions: true, - isRiskyHostsEnabled: false, }); expect(tabs).toHaveProperty(HostsTableType.hosts); expect(tabs).toHaveProperty(HostsTableType.uncommonProcesses); @@ -31,21 +29,9 @@ describe('navTabsHosts', () => { expect(tabs).toHaveProperty(HostsTableType.events); }); - test('it should skip risk tab if without hostRisk', () => { + test('it should display risk tab', () => { const tabs = navTabsHosts({ hasMlUserPermissions: false, - isRiskyHostsEnabled: false, - }); - expect(tabs).toHaveProperty(HostsTableType.hosts); - expect(tabs).toHaveProperty(HostsTableType.uncommonProcesses); - expect(tabs).not.toHaveProperty(HostsTableType.risk); - expect(tabs).toHaveProperty(HostsTableType.events); - }); - - test('it should display risk tab if with hostRisk', () => { - const tabs = navTabsHosts({ - hasMlUserPermissions: false, - isRiskyHostsEnabled: true, }); expect(tabs).toHaveProperty(HostsTableType.hosts); expect(tabs).toHaveProperty(HostsTableType.uncommonProcesses); diff --git a/x-pack/plugins/security_solution/public/explore/hosts/pages/nav_tabs.tsx b/x-pack/plugins/security_solution/public/explore/hosts/pages/nav_tabs.tsx index 3ad471afcf85e..1695b0ff101eb 100644 --- a/x-pack/plugins/security_solution/public/explore/hosts/pages/nav_tabs.tsx +++ b/x-pack/plugins/security_solution/public/explore/hosts/pages/nav_tabs.tsx @@ -15,11 +15,9 @@ const getTabsOnHostsUrl = (tabName: HostsTableType) => `${HOSTS_PATH}/${tabName} export const navTabsHosts = ({ hasMlUserPermissions, - isRiskyHostsEnabled, isEnterprise, }: { hasMlUserPermissions: boolean; - isRiskyHostsEnabled: boolean; isEnterprise?: boolean; }): HostsNavTab => { const hiddenTabs = []; @@ -67,10 +65,6 @@ export const navTabsHosts = ({ hiddenTabs.push(HostsTableType.anomalies); } - if (!isRiskyHostsEnabled) { - hiddenTabs.push(HostsTableType.risk); - } - if (!isEnterprise) { hiddenTabs.push(HostsTableType.sessions); } diff --git a/x-pack/plugins/security_solution/public/explore/hosts/pages/navigation/host_risk_score_tab_body.tsx b/x-pack/plugins/security_solution/public/explore/hosts/pages/navigation/host_risk_score_tab_body.tsx index 28f0a8dbed776..5e6c8d8778f80 100644 --- a/x-pack/plugins/security_solution/public/explore/hosts/pages/navigation/host_risk_score_tab_body.tsx +++ b/x-pack/plugins/security_solution/public/explore/hosts/pages/navigation/host_risk_score_tab_body.tsx @@ -8,6 +8,7 @@ import React, { useEffect, useMemo, useState } from 'react'; import { EuiPanel } from '@elastic/eui'; import { noop } from 'lodash/fp'; +import { useUpsellingComponent } from '../../../../common/hooks/use_upselling'; import { RiskEnginePrivilegesCallOut } from '../../../../entity_analytics/components/risk_engine_privileges_callout'; import { useMissingRiskEnginePrivileges } from '../../../../entity_analytics/hooks/use_missing_risk_engine_privileges'; import { HostRiskScoreQueryId } from '../../../../entity_analytics/common/utils'; @@ -96,6 +97,12 @@ export const HostRiskScoreQueryTabBody = ({ isDeprecated: isDeprecated && !loading, }; + const RiskScoreUpsell = useUpsellingComponent('entity_analytics_panel'); + + if (RiskScoreUpsell) { + return ; + } + if (!privileges.isLoading && !privileges.hasAllRequiredPrivileges) { return ( diff --git a/x-pack/plugins/security_solution/public/explore/users/pages/details/index.tsx b/x-pack/plugins/security_solution/public/explore/users/pages/details/index.tsx index 4e61c7083d038..87af28648bdd8 100644 --- a/x-pack/plugins/security_solution/public/explore/users/pages/details/index.tsx +++ b/x-pack/plugins/security_solution/public/explore/users/pages/details/index.tsx @@ -76,7 +76,6 @@ import { UsersType } from '../../store/model'; import { hasMlUserPermissions } from '../../../../../common/machine_learning/has_ml_user_permissions'; import { useMlCapabilities } from '../../../../common/components/ml/hooks/use_ml_capabilities'; import { EmptyPrompt } from '../../../../common/components/empty_prompt'; -import { useHasSecurityCapability } from '../../../../helper_hooks'; import { useRefetchOverviewPageRiskScore } from '../../../../entity_analytics/api/hooks/use_refetch_overview_page_risk_score'; const QUERY_ID = 'UsersDetailsQueryId'; @@ -87,7 +86,6 @@ const UsersDetailsComponent: React.FC = ({ usersDetailsPagePath, }) => { const dispatch = useDispatch(); - const hasEntityAnalyticsCapability = useHasSecurityCapability('entity-analytics'); const getTable = useMemo(() => dataTableSelectors.getTableByIdSelector(), []); const graphEventId = useShallowEqualSelector( (state) => (getTable(state, TableId.hostsPageEvents) ?? timelineDefaults).graphEventId @@ -285,11 +283,7 @@ const UsersDetailsComponent: React.FC = ({ )} { test('it should not display anomalies tab if user has no ml permission', () => { - const tabs = navTabsUsersDetails('username', false, true); + const tabs = navTabsUsersDetails('username', false); expect(tabs).not.toHaveProperty(UsersTableType.anomalies); expect(tabs).toHaveProperty(UsersTableType.risk); }); - - test('it should not display risk tab if isRiskyUserEnabled disabled', () => { - const tabs = navTabsUsersDetails('username', true, false); - // expect(tabs).toHaveProperty(UsersTableType.allUsers); - expect(tabs).toHaveProperty(UsersTableType.anomalies); - expect(tabs).not.toHaveProperty(UsersTableType.risk); - }); }); diff --git a/x-pack/plugins/security_solution/public/explore/users/pages/details/nav_tabs.tsx b/x-pack/plugins/security_solution/public/explore/users/pages/details/nav_tabs.tsx index e4e275fd79a9b..c05f1562975a0 100644 --- a/x-pack/plugins/security_solution/public/explore/users/pages/details/nav_tabs.tsx +++ b/x-pack/plugins/security_solution/public/explore/users/pages/details/nav_tabs.tsx @@ -16,8 +16,7 @@ const getTabsOnUsersDetailsUrl = (userName: string, tabName: UsersTableType) => export const navTabsUsersDetails = ( userName: string, - hasMlUserPermissions: boolean, - isRiskyUserEnabled: boolean + hasMlUserPermissions: boolean ): UsersDetailsNavTab => { const hiddenTabs = []; @@ -52,9 +51,5 @@ export const navTabsUsersDetails = ( hiddenTabs.push(UsersTableType.anomalies); } - if (!isRiskyUserEnabled) { - hiddenTabs.push(UsersTableType.risk); - } - return omit(hiddenTabs, userDetailsNavTabs); }; diff --git a/x-pack/plugins/security_solution/public/explore/users/pages/nav_tabs.test.tsx b/x-pack/plugins/security_solution/public/explore/users/pages/nav_tabs.test.tsx index 492f85ec7ec02..a5ba7b96049a3 100644 --- a/x-pack/plugins/security_solution/public/explore/users/pages/nav_tabs.test.tsx +++ b/x-pack/plugins/security_solution/public/explore/users/pages/nav_tabs.test.tsx @@ -10,23 +10,16 @@ import { navTabsUsers } from './nav_tabs'; describe('navTabsUsers', () => { test('it should display all tabs', () => { - const tabs = navTabsUsers(true, true); + const tabs = navTabsUsers(true); expect(tabs).toHaveProperty(UsersTableType.allUsers); expect(tabs).toHaveProperty(UsersTableType.anomalies); expect(tabs).toHaveProperty(UsersTableType.risk); }); test('it should not display anomalies tab if user has no ml permission', () => { - const tabs = navTabsUsers(false, true); + const tabs = navTabsUsers(false); expect(tabs).toHaveProperty(UsersTableType.allUsers); expect(tabs).not.toHaveProperty(UsersTableType.anomalies); expect(tabs).toHaveProperty(UsersTableType.risk); }); - - test('it should not display risk tab if isRiskyUserEnabled disabled', () => { - const tabs = navTabsUsers(true, false); - expect(tabs).toHaveProperty(UsersTableType.allUsers); - expect(tabs).toHaveProperty(UsersTableType.anomalies); - expect(tabs).not.toHaveProperty(UsersTableType.risk); - }); }); diff --git a/x-pack/plugins/security_solution/public/explore/users/pages/nav_tabs.tsx b/x-pack/plugins/security_solution/public/explore/users/pages/nav_tabs.tsx index 676fc3d506e5c..d7f91cfe1c9e0 100644 --- a/x-pack/plugins/security_solution/public/explore/users/pages/nav_tabs.tsx +++ b/x-pack/plugins/security_solution/public/explore/users/pages/nav_tabs.tsx @@ -13,10 +13,7 @@ import { USERS_PATH } from '../../../../common/constants'; const getTabsOnUsersUrl = (tabName: UsersTableType) => `${USERS_PATH}/${tabName}`; -export const navTabsUsers = ( - hasMlUserPermissions: boolean, - isRiskyUserEnabled: boolean -): UsersNavTab => { +export const navTabsUsers = (hasMlUserPermissions: boolean): UsersNavTab => { const hiddenTabs = []; const userNavTabs = { @@ -56,9 +53,5 @@ export const navTabsUsers = ( hiddenTabs.push(UsersTableType.anomalies); } - if (!isRiskyUserEnabled) { - hiddenTabs.push(UsersTableType.risk); - } - return omit(hiddenTabs, userNavTabs); }; diff --git a/x-pack/plugins/security_solution/public/explore/users/pages/users.tsx b/x-pack/plugins/security_solution/public/explore/users/pages/users.tsx index 41f974971b0e1..7f5167c29d91a 100644 --- a/x-pack/plugins/security_solution/public/explore/users/pages/users.tsx +++ b/x-pack/plugins/security_solution/public/explore/users/pages/users.tsx @@ -49,7 +49,6 @@ import { hasMlUserPermissions } from '../../../../common/machine_learning/has_ml import { useMlCapabilities } from '../../../common/components/ml/hooks/use_ml_capabilities'; import { EmptyPrompt } from '../../../common/components/empty_prompt'; import { userNameExistsFilter } from './details/helpers'; -import { useHasSecurityCapability } from '../../../helper_hooks'; const ID = 'UsersQueryId'; @@ -156,11 +155,7 @@ const UsersComponent = () => { ); const capabilities = useMlCapabilities(); - const hasEntityAnalyticsCapability = useHasSecurityCapability('entity-analytics'); - const navTabs = useMemo( - () => navTabsUsers(hasMlUserPermissions(capabilities), hasEntityAnalyticsCapability), - [capabilities, hasEntityAnalyticsCapability] - ); + const navTabs = useMemo(() => navTabsUsers(hasMlUserPermissions(capabilities)), [capabilities]); return ( <> diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.test.tsx index b54d195abb278..46f22886c8b58 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.test.tsx @@ -116,7 +116,7 @@ describe('', () => { // TODO: 8.15 simplify when `agentStatusClientEnabled` FF is enabled and removed it.each(Object.keys(hooksToMock))( - 'should render SentinelOne agent status cell if field is agent.status and `origialField` is `observer.serial_number` with %s hook', + 'should render SentinelOne agent status cell if field is agent.status and `originalField` is `observer.serial_number` with %s hook', (hookName) => { const hook = hooksToMock[hookName]; useAgentStatusHookMock.mockImplementation(() => hook); @@ -139,7 +139,30 @@ describe('', () => { expect(getByTestId(HIGHLIGHTED_FIELDS_AGENT_STATUS_CELL_TEST_ID)).toBeInTheDocument(); } ); + it.each(Object.keys(hooksToMock))( + 'should render Crowdstrike agent status cell if field is agent.status and `originalField` is `crowdstrike.event.DeviceId` with %s hook', + (hookName) => { + const hook = hooksToMock[hookName]; + useAgentStatusHookMock.mockImplementation(() => hook); + (hook as jest.Mock).mockReturnValue({ + isFetched: true, + isLoading: false, + }); + + const { getByTestId } = render( + + + + ); + + expect(getByTestId(HIGHLIGHTED_FIELDS_AGENT_STATUS_CELL_TEST_ID)).toBeInTheDocument(); + } + ); it('should not render if values is null', () => { const { container } = render( diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.tsx index 11031638d67fd..be495a6b16df6 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/highlighted_fields_cell.tsx @@ -9,12 +9,14 @@ import type { VFC } from 'react'; import React, { memo, useCallback, useMemo } from 'react'; import { EuiFlexItem, EuiLink } from '@elastic/eui'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import type { ResponseActionAgentType } from '../../../../../common/endpoint/service/response_actions/constants'; import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { SENTINEL_ONE_AGENT_ID_FIELD } from '../../../../common/utils/sentinelone_alert_check'; import { AgentStatus, EndpointAgentStatusById, } from '../../../../common/components/agents/agent_status'; +import { CROWDSTRIKE_AGENT_ID_FIELD } from '../../../../common/utils/crowdstrike_alert_check'; import { useRightPanelContext } from '../context'; import { AGENT_STATUS_FIELD_NAME, @@ -81,19 +83,13 @@ export interface HighlightedFieldsCellProps { } const FieldsAgentStatus = memo( - ({ - value, - isSentinelOneAgentIdField, - }: { - value: string | undefined; - isSentinelOneAgentIdField: boolean; - }) => { + ({ value, agentType }: { value: string | undefined; agentType: ResponseActionAgentType }) => { const agentStatusClientEnabled = useIsExperimentalFeatureEnabled('agentStatusClientEnabled'); - if (isSentinelOneAgentIdField || agentStatusClientEnabled) { + if (agentType !== 'endpoint' || agentStatusClientEnabled) { return ( ); @@ -124,6 +120,19 @@ export const HighlightedFieldsCell: VFC = ({ () => originalField === SENTINEL_ONE_AGENT_ID_FIELD, [originalField] ); + const isCrowdstrikeAgentIdField = useMemo( + () => originalField === CROWDSTRIKE_AGENT_ID_FIELD, + [originalField] + ); + const agentType: ResponseActionAgentType = useMemo(() => { + if (isSentinelOneAgentIdField) { + return 'sentinel_one'; + } + if (isCrowdstrikeAgentIdField) { + return 'crowdstrike'; + } + return 'endpoint'; + }, [isCrowdstrikeAgentIdField, isSentinelOneAgentIdField]); return ( <> @@ -138,10 +147,7 @@ export const HighlightedFieldsCell: VFC = ({ {field === HOST_NAME_FIELD_NAME || field === USER_NAME_FIELD_NAME ? ( ) : field === AGENT_STATUS_FIELD_NAME ? ( - + ) : ( {value} )} diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_highlighted_fields.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_highlighted_fields.test.tsx index cc53f8c9a1fe1..3a18b49a0fc17 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_highlighted_fields.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_highlighted_fields.test.tsx @@ -120,6 +120,27 @@ describe('useHighlightedFields', () => { }); }); + it('should omit crowdstrike agent id field if data is not crowdstrike alert', () => { + const hookResult = renderHook(() => + useHighlightedFields({ + dataFormattedForFieldBrowser: dataFormattedForFieldBrowser.concat({ + category: 'crowdstrike', + field: 'crowdstrike.event.DeviceId', + values: ['expectedCrowdstrikeAgentId'], + originalValue: ['expectedCrowdstrikeAgentId'], + isObjectArray: false, + }), + investigationFields: ['agent.status', 'crowdstrike.event.DeviceId'], + }) + ); + + expect(hookResult.result.current).toEqual({ + 'kibana.alert.rule.type': { + values: ['query'], + }, + }); + }); + it('should return sentinelone agent id field if data is s1 alert', () => { const hookResult = renderHook(() => useHighlightedFields({ @@ -152,4 +173,37 @@ describe('useHighlightedFields', () => { }, }); }); + + it('should return crowdstrike agent id field if data is crowdstrike alert', () => { + const hookResult = renderHook(() => + useHighlightedFields({ + dataFormattedForFieldBrowser: dataFormattedForFieldBrowser.concat([ + { + category: 'event', + field: 'event.module', + values: ['crowdstrike'], + originalValue: ['crowdstrike'], + isObjectArray: false, + }, + { + category: 'crowdstrike', + field: 'crowdstrike.event.DeviceId', + values: ['expectedCrowdstrikeAgentId'], + originalValue: ['expectedCrowdstrikeAgentId'], + isObjectArray: false, + }, + ]), + investigationFields: ['agent.status', 'crowdstrike.event.DeviceId'], + }) + ); + + expect(hookResult.result.current).toEqual({ + 'kibana.alert.rule.type': { + values: ['query'], + }, + 'crowdstrike.event.DeviceId': { + values: ['expectedCrowdstrikeAgentId'], + }, + }); + }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_highlighted_fields.ts b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_highlighted_fields.ts index 3950788bcec2d..c60bb96c77974 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_highlighted_fields.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_highlighted_fields.ts @@ -8,6 +8,10 @@ import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; import { find, isEmpty } from 'lodash/fp'; import { ALERT_RULE_TYPE } from '@kbn/rule-data-utils'; +import { + CROWDSTRIKE_AGENT_ID_FIELD, + isAlertFromCrowdstrikeEvent, +} from '../../../../common/utils/crowdstrike_alert_check'; import { SENTINEL_ONE_AGENT_ID_FIELD, isAlertFromSentinelOneEvent, @@ -111,6 +115,14 @@ export const useHighlightedFields = ({ return acc; } + // if the field is crowdstrike.event.DeviceId and the event is not a crowdstrike event we skip it + if ( + field.id === CROWDSTRIKE_AGENT_ID_FIELD && + !isAlertFromCrowdstrikeEvent({ data: dataFormattedForFieldBrowser }) + ) { + return acc; + } + return { ...acc, [field.id]: { diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/components/offline_callout.test.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/components/offline_callout.test.tsx index c28c15c226a82..ffa739ede735b 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/components/offline_callout.test.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/components/offline_callout.test.tsx @@ -6,6 +6,7 @@ */ import type { ResponseActionAgentType } from '../../../../../common/endpoint/service/response_actions/constants'; +import { RESPONSE_ACTION_AGENT_TYPE } from '../../../../../common/endpoint/service/response_actions/constants'; import React from 'react'; import type { HostInfo } from '../../../../../common/endpoint/types'; import { HostStatus } from '../../../../../common/endpoint/types'; @@ -60,14 +61,14 @@ describe('Responder offline callout', () => { jest.clearAllMocks(); }); - it.each(['endpoint', 'sentinel_one'] as ResponseActionAgentType[])( + it.each(RESPONSE_ACTION_AGENT_TYPE)( 'should be visible when agent type is %s and host is offline', (agentType) => { if (agentType === 'endpoint') { getEndpointDetails.mockReturnValue({ data: { ...endpointDetails, host_status: HostStatus.OFFLINE }, }); - } else if (agentType === 'sentinel_one') { + } else { mockHook.mockReturnValue({ data: { '1234': { @@ -82,14 +83,14 @@ describe('Responder offline callout', () => { } ); - it.each(['endpoint', 'sentinel_one'] as ResponseActionAgentType[])( + it.each(RESPONSE_ACTION_AGENT_TYPE)( 'should not be visible when agent type is %s and host is online', (agentType) => { if (agentType === 'endpoint') { getEndpointDetails.mockReturnValue({ data: { ...endpointDetails, host_status: HostStatus.HEALTHY }, }); - } else if (agentType === 'sentinel_one') { + } else { mockHook.mockReturnValue({ data: { '1234': { diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/components/offline_callout.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/components/offline_callout.tsx index b630af8959328..d18a8526fb3eb 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/components/offline_callout.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/components/offline_callout.tsx @@ -24,7 +24,9 @@ interface OfflineCalloutProps { export const OfflineCallout = memo(({ agentType, endpointId, hostName }) => { const isEndpointAgent = agentType === 'endpoint'; const isSentinelOneAgent = agentType === 'sentinel_one'; + const isCrowdstrikeAgent = agentType === 'crowdstrike'; const getAgentStatus = useAgentStatusHook(); + const agentStatusClientEnabled = useIsExperimentalFeatureEnabled('agentStatusClientEnabled'); const isSentinelOneV1Enabled = useIsExperimentalFeatureEnabled( 'responseActionsSentinelOneV1Enabled' ); @@ -32,27 +34,40 @@ export const OfflineCallout = memo(({ agentType, endpointId const sentinelOneManualHostActionsEnabled = useIsExperimentalFeatureEnabled( 'sentinelOneManualHostActionsEnabled' ); + const crowdstrikeManualHostActionsEnabled = useIsExperimentalFeatureEnabled( + 'responseActionsCrowdstrikeManualHostIsolationEnabled' + ); const { data: endpointDetails } = useGetEndpointDetails(endpointId, { refetchInterval: 10000, - enabled: isEndpointAgent, + enabled: isEndpointAgent && !agentStatusClientEnabled, }); const { data } = getAgentStatus([endpointId], agentType, { - enabled: sentinelOneManualHostActionsEnabled && isSentinelOneAgent, + enabled: + (sentinelOneManualHostActionsEnabled && isSentinelOneAgent) || + (crowdstrikeManualHostActionsEnabled && isCrowdstrikeAgent) || + (isEndpointAgent && agentStatusClientEnabled), }); - - // TODO: simplify this to use the yet to be implemented agentStatus API hook const showOfflineCallout = useMemo( () => (isEndpointAgent && endpointDetails?.host_status === HostStatus.OFFLINE) || - (isSentinelOneAgent && data?.[endpointId].status === HostStatus.OFFLINE), - [data, endpointDetails?.host_status, endpointId, isEndpointAgent, isSentinelOneAgent] + (isSentinelOneAgent && data?.[endpointId].status === HostStatus.OFFLINE) || + (isCrowdstrikeAgent && data?.[endpointId].status === HostStatus.OFFLINE), + [ + data, + endpointDetails?.host_status, + endpointId, + isEndpointAgent, + isCrowdstrikeAgent, + isSentinelOneAgent, + ] ); if ( (isEndpointAgent && !endpointDetails) || - (isSentinelOneV1Enabled && isSentinelOneAgent && !data) + (isSentinelOneV1Enabled && isSentinelOneAgent && !data) || + (crowdstrikeManualHostActionsEnabled && isCrowdstrikeAgent && !data) ) { return null; } diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint_role_rbac.feature_flag.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint_role_rbac.feature_flag.cy.ts new file mode 100644 index 0000000000000..e7c98df4e735f --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint_role_rbac.feature_flag.cy.ts @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { closeAllToasts } from '../tasks/toasts'; +import { login, ROLE } from '../tasks/login'; +import { loadPage } from '../tasks/common'; + +describe( + 'When defining a kibana role for Endpoint security access', + { + env: { + ftrConfig: { + kbnServerArgs: [ + `--xpack.securitySolution.enableExperimental=${JSON.stringify([ + 'responseActionScanEnabled', + ])}`, + ], + }, + }, + tags: '@ess', + }, + () => { + const getAllSubFeatureRows = (): Cypress.Chainable> => { + return cy + .get('#featurePrivilegeControls_siem') + .findByTestSubj('mutexSubFeaturePrivilegeControl') + .closest('.euiFlexGroup'); + }; + + beforeEach(() => { + login(ROLE.system_indices_superuser); + loadPage('/app/management/security/roles/edit'); + closeAllToasts(); + cy.getByTestSubj('addSpacePrivilegeButton').click(); + cy.getByTestSubj('featureCategoryButton_securitySolution').closest('button').click(); + cy.get('.featurePrivilegeName:contains("Security")').closest('button').click(); + }); + + it('should display RBAC entries with expected controls', () => { + getAllSubFeatureRows() + .then(($subFeatures) => { + const featureRows: string[] = []; + $subFeatures.each((_, $subFeature) => { + featureRows.push($subFeature.textContent ?? ''); + }); + + return featureRows; + }) + .should('deep.equal', [ + 'Endpoint List Displays all hosts running Elastic Defend and their relevant integration details.Endpoint List sub-feature privilegeAllReadNone', + 'Trusted Applications Helps mitigate conflicts with other software, usually other antivirus or endpoint security applications.Trusted Applications sub-feature privilegeAllReadNone', + 'Host Isolation Exceptions Add specific IP addresses that isolated hosts are still allowed to communicate with, even when isolated from the rest of the network.Host Isolation Exceptions sub-feature privilegeAllReadNone', + 'Blocklist Extend Elastic Defend’s protection against malicious processes and protect against potentially harmful applications.Blocklist sub-feature privilegeAllReadNone', + 'Event Filters Filter out endpoint events that you do not need or want stored in Elasticsearch.Event Filters sub-feature privilegeAllReadNone', + 'Elastic Defend Policy Management Access the Elastic Defend integration policy to configure protections, event collection, and advanced policy features.Elastic Defend Policy Management sub-feature privilegeAllReadNone', + 'Response Actions History Access the history of response actions performed on endpoints.Response Actions History sub-feature privilegeAllReadNone', + 'Host Isolation Perform the "isolate" and "release" response actions.Host Isolation sub-feature privilegeAllNone', + 'Process Operations Perform process-related response actions in the response console.Process Operations sub-feature privilegeAllNone', + 'File Operations Perform file-related response actions in the response console.File Operations sub-feature privilegeAllNone', + 'Execute Operations Perform script execution response actions in the response console.Execute Operations sub-feature privilegeAllNone', + 'Scan Operations Perform folder scan response actions in the response console.Scan Operations sub-feature privilegeAllNone', + ]); + }); + } +); diff --git a/x-pack/plugins/security_solution/public/management/hooks/agents/use_get_agent_status.tsx b/x-pack/plugins/security_solution/public/management/hooks/agents/use_get_agent_status.tsx index 066c9a3c53215..5aa1d6b5f6b21 100644 --- a/x-pack/plugins/security_solution/public/management/hooks/agents/use_get_agent_status.tsx +++ b/x-pack/plugins/security_solution/public/management/hooks/agents/use_get_agent_status.tsx @@ -33,6 +33,7 @@ export const useGetSentinelOneAgentStatus = ( queryKey: ['get-agent-status', agentIds], refetchInterval: 5000, ...options, + enabled: agentType === 'sentinel_one', queryFn: () => http .get<{ data: AgentStatusInfo }>(AGENT_STATUS_ROUTE, { diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/__snapshots__/custom_timeline_data_grid_body.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/__snapshots__/custom_timeline_data_grid_body.test.tsx.snap index 3845ad9801abd..2c8c9d593b775 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/__snapshots__/custom_timeline_data_grid_body.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/__snapshots__/custom_timeline_data_grid_body.test.tsx.snap @@ -212,7 +212,7 @@ exports[`CustomTimelineDataGridBody should render exactly as snapshots 1`] = ` test added a note

note diff --git a/x-pack/plugins/security_solution/scripts/endpoint/agent_policy_generator/index.ts b/x-pack/plugins/security_solution/scripts/endpoint/agent_policy_generator/index.ts index 104bf337be5d3..afe370e1bda72 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/agent_policy_generator/index.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/agent_policy_generator/index.ts @@ -59,7 +59,6 @@ const agentPolicyGenerator: RunFn = async ({ flags, log }) => { username: flags.username as string, password: flags.password as string, apiKey: flags.apikey as string, - noCertForSsl: true, log, }); diff --git a/x-pack/plugins/security_solution/scripts/endpoint/api_emulator/emulator_plugins/crowdstrike/index.ts b/x-pack/plugins/security_solution/scripts/endpoint/api_emulator/emulator_plugins/crowdstrike/index.ts index cdfbdff81c84b..b4f337a52a425 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/api_emulator/emulator_plugins/crowdstrike/index.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/api_emulator/emulator_plugins/crowdstrike/index.ts @@ -5,21 +5,18 @@ * 2.0. */ +import type { ExternalEdrServerEmulatorCoreServices } from '../../external_edr_server_emulator.types'; import type { EmulatorServerPlugin } from '../../lib/emulator_server.types'; +import { getCrowdstrikeRouteDefinitions } from './routes'; -export const getCrowdstrikeEmulator = () => { - const plugin: EmulatorServerPlugin = { - name: 'crowdstrike', - register({ router }) { - router.route({ - path: '/', - method: 'GET', - handler: () => { - return { message: `Live! But not implemented` }; - }, - }); - }, - }; +export const getCrowdstrikeEmulator = + (): EmulatorServerPlugin => { + const plugin: EmulatorServerPlugin = { + name: 'crowdstrike', + register({ router, expose, services }) { + router.route(getCrowdstrikeRouteDefinitions()); + }, + }; - return plugin; -}; + return plugin; + }; diff --git a/x-pack/plugins/security_solution/scripts/endpoint/api_emulator/emulator_plugins/crowdstrike/mocks.ts b/x-pack/plugins/security_solution/scripts/endpoint/api_emulator/emulator_plugins/crowdstrike/mocks.ts new file mode 100644 index 0000000000000..cab12ebaeac1a --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/api_emulator/emulator_plugins/crowdstrike/mocks.ts @@ -0,0 +1,148 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { + CrowdstrikeBaseApiResponse, + CrowdstrikeGetAgentOnlineStatusResponse, + CrowdstrikeGetAgentsResponse, +} from '@kbn/stack-connectors-plugin/common/crowdstrike/types'; +import { merge } from 'lodash'; + +export const createCrowdstrikeGetAgentsApiResponseMock = ( + data: CrowdstrikeBaseApiResponse['resources'][number] +) => { + return { + meta: { + query_time: 0.001831479, + powered_by: 'device-api', + trace_id: '4567898765-432423432432-42342342', + }, + errors: null, + resources: data, + }; +}; + +export const createCrowdstrikeAgentDetailsMock = ( + overrides: Partial = {} +): CrowdstrikeGetAgentsResponse['resources'][number] => { + return merge( + { + device_id: '0eec3717b2eb472195bbb3964c05cfd3', + cid: '234567890', + agent_load_flags: '0', + agent_local_time: '2024-03-18T22:21:00.173Z', + agent_version: '7.07.16206.0', + bios_manufacturer: 'Amazon EC2', + bios_version: '1.0', + config_id_base: '65994753', + config_id_build: '16206', + config_id_platform: '8', + cpu_signature: '8392466', + cpu_vendor: '1', + external_ip: '18.157.150.216', + mac_address: '03-f4-f4-f4-f4', + instance_id: 'i-456789', + service_provider: 'AWS_EC2_V2', + service_provider_account_id: '23456789', + hostname: 'Crowdstrike-1460', + first_seen: '2024-03-15T13:18:56Z', + last_login_timestamp: '2024-03-15T22:11:47Z', + last_login_user: 'testuser', + last_login_uid: '1002', + last_seen: '2024-03-20T07:19:01Z', + local_ip: '172.31.200.45', + major_version: '5', + minor_version: '14', + os_version: 'RHEL 9.3', + platform_id: '3', + platform_name: 'Linux', + policies: [ + { + policy_type: 'prevention', + policy_id: '234234234234', + applied: true, + settings_hash: 'f0e04444', + assigned_date: '2024-03-15T13:20:02.25821602Z', + applied_date: '2024-03-15T13:20:16.804783955Z', + rule_groups: [], + }, + ], + reduced_functionality_mode: 'no', + device_policies: { + prevention: { + policy_type: 'prevention', + policy_id: '234234234234', + applied: true, + settings_hash: 'f0e04444', + assigned_date: '2024-03-15T13:20:02.25821602Z', + applied_date: '2024-03-15T13:20:16.804783955Z', + rule_groups: [], + }, + sensor_update: { + policy_type: 'sensor-update', + policy_id: '234234234234', + applied: true, + settings_hash: 'tagged|5;', + assigned_date: '2024-03-15T13:20:02.258765734Z', + applied_date: '2024-03-15T13:23:53.773752711Z', + uninstall_protection: 'UNKNOWN', + }, + global_config: { + policy_type: 'globalconfig', + policy_id: '234234234234', + applied: true, + settings_hash: 'f0e04444', + assigned_date: '2024-03-18T22:21:01.50638371Z', + applied_date: '2024-03-18T22:21:30.565040189Z', + }, + remote_response: { + policy_type: 'remote-response', + policy_id: '234234234234', + applied: true, + settings_hash: 'f0e04444', + assigned_date: '2024-03-15T13:20:02.258285018Z', + applied_date: '2024-03-15T13:20:17.016591803Z', + }, + }, + groups: [], + group_hash: '45678909876545678', + product_type_desc: 'Server', + provision_status: 'NotProvisioned', + serial_number: '345678765-35d6-e704-1723-423423432', + status: 'containment_pending', + system_manufacturer: 'Amazon EC2', + system_product_name: 't3a.medium', + tags: [], + modified_timestamp: '2024-03-20T07:19:45Z', + meta: { + version: '484', + version_string: '9:33384301139', + }, + zone_group: 'eu-central-1a', + kernel_version: '5.14.0-234234el9_3.x86_64', + chassis_type: '1', + chassis_type_desc: 'Other', + connection_ip: '172.31.200.45', + default_gateway_ip: '172.31.200.1', + connection_mac_address: '02-e8-f1-0e-b7-c4', + linux_sensor_mode: 'Kernel Mode', + deployment_type: 'Standard', + }, + overrides + ); +}; + +export const createCrowdstrikeGetAgentOnlineStatusDetailsMock: ( + overrides: Partial +) => CrowdstrikeGetAgentOnlineStatusResponse['resources'][number] = (overrides) => { + return merge( + { + state: 'online', + id: 'ae86ad7402404048ac9b8d94db8f7ba2', + }, + overrides + ); +}; diff --git a/x-pack/plugins/security_solution/scripts/endpoint/api_emulator/emulator_plugins/crowdstrike/routes/get_agent_details_route.ts b/x-pack/plugins/security_solution/scripts/endpoint/api_emulator/emulator_plugins/crowdstrike/routes/get_agent_details_route.ts new file mode 100644 index 0000000000000..84e5f42783f3a --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/api_emulator/emulator_plugins/crowdstrike/routes/get_agent_details_route.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { buildCrowdstrikeRoutePath } from './utils'; +import type { ExternalEdrServerEmulatorRouteHandlerMethod } from '../../../external_edr_server_emulator.types'; +import type { EmulatorServerRouteDefinition } from '../../../lib/emulator_server.types'; +import { + createCrowdstrikeAgentDetailsMock, + createCrowdstrikeGetAgentsApiResponseMock, +} from '../mocks'; + +export const getAgentDetailsRouteDefinition = (): EmulatorServerRouteDefinition => { + return { + path: buildCrowdstrikeRoutePath('/devices/entities/devices/v2'), + method: 'GET', + handler: getAgentDetailsHandler, + }; +}; + +const getAgentDetailsHandler: ExternalEdrServerEmulatorRouteHandlerMethod<{}> = async () => { + return createCrowdstrikeGetAgentsApiResponseMock([createCrowdstrikeAgentDetailsMock({})]); +}; diff --git a/x-pack/plugins/security_solution/scripts/endpoint/api_emulator/emulator_plugins/crowdstrike/routes/get_agent_online_status_route.ts b/x-pack/plugins/security_solution/scripts/endpoint/api_emulator/emulator_plugins/crowdstrike/routes/get_agent_online_status_route.ts new file mode 100644 index 0000000000000..59c5d9a18a1f9 --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/api_emulator/emulator_plugins/crowdstrike/routes/get_agent_online_status_route.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { buildCrowdstrikeRoutePath } from './utils'; +import type { ExternalEdrServerEmulatorRouteHandlerMethod } from '../../../external_edr_server_emulator.types'; +import type { EmulatorServerRouteDefinition } from '../../../lib/emulator_server.types'; +import { createCrowdstrikeGetAgentOnlineStatusDetailsMock } from '../mocks'; + +export const getAgentOnlineStatusRouteDefinition = (): EmulatorServerRouteDefinition => { + return { + path: buildCrowdstrikeRoutePath('/devices/entities/online-state/v1'), + method: 'GET', + handler: getAgentOnlineStatusHandler, + }; +}; + +const getAgentOnlineStatusHandler: ExternalEdrServerEmulatorRouteHandlerMethod<{}> = async () => { + return { + resources: [createCrowdstrikeGetAgentOnlineStatusDetailsMock({})], + meta: { + query_time: 123, + powered_by: 'test', + trace_id: 'test', + }, + errors: [], + }; +}; diff --git a/x-pack/plugins/security_solution/scripts/endpoint/api_emulator/emulator_plugins/crowdstrike/routes/get_token_route.ts b/x-pack/plugins/security_solution/scripts/endpoint/api_emulator/emulator_plugins/crowdstrike/routes/get_token_route.ts new file mode 100644 index 0000000000000..6629c33974b04 --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/api_emulator/emulator_plugins/crowdstrike/routes/get_token_route.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { buildCrowdstrikeRoutePath } from './utils'; +import type { ExternalEdrServerEmulatorRouteHandlerMethod } from '../../../external_edr_server_emulator.types'; +import type { EmulatorServerRouteDefinition } from '../../../lib/emulator_server.types'; + +export const getTokenRouteDefinition = (): EmulatorServerRouteDefinition => { + return { + path: buildCrowdstrikeRoutePath('/oauth2/token'), + method: 'POST', + handler: getTokenHandler, + }; +}; + +const getTokenHandler: ExternalEdrServerEmulatorRouteHandlerMethod<{}> = async () => { + return { + access_token: 'testtoken', + expires_in: 123, + token_type: 'bearer', + id_token: 'test', + issued_token_type: 'test', + refresh_token: 'test', + scope: 'test', + }; +}; diff --git a/x-pack/plugins/security_solution/scripts/endpoint/api_emulator/emulator_plugins/crowdstrike/routes/host_actions_route.ts b/x-pack/plugins/security_solution/scripts/endpoint/api_emulator/emulator_plugins/crowdstrike/routes/host_actions_route.ts new file mode 100644 index 0000000000000..2c648213a3f09 --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/api_emulator/emulator_plugins/crowdstrike/routes/host_actions_route.ts @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { CrowdstrikeHostActionsParams } from '@kbn/stack-connectors-plugin/common/crowdstrike/types'; +import { buildCrowdstrikeRoutePath } from './utils'; +import type { ExternalEdrServerEmulatorRouteHandlerMethod } from '../../../external_edr_server_emulator.types'; +import type { EmulatorServerRouteDefinition } from '../../../lib/emulator_server.types'; + +export const hostActionsRouteDefinition = (): EmulatorServerRouteDefinition => { + return { + path: buildCrowdstrikeRoutePath('/devices/entities/devices-actions/v2'), + method: 'POST', + handler: hostActionsHandler, + }; +}; + +const hostActionsHandler: ExternalEdrServerEmulatorRouteHandlerMethod< + {}, + CrowdstrikeHostActionsParams +> = async () => { + return { + resources: [ + { + id: 'test', + path: 'test', + }, + ], + + meta: { + query_time: 123, + powered_by: 'test', + trace_id: 'test', + }, + errors: [], + }; +}; diff --git a/x-pack/plugins/security_solution/scripts/endpoint/api_emulator/emulator_plugins/crowdstrike/routes/index.ts b/x-pack/plugins/security_solution/scripts/endpoint/api_emulator/emulator_plugins/crowdstrike/routes/index.ts new file mode 100644 index 0000000000000..1da4f435aae4c --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/endpoint/api_emulator/emulator_plugins/crowdstrike/routes/index.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getTokenRouteDefinition } from './get_token_route'; +import type { EmulatorServerRouteDefinition } from '../../../lib/emulator_server.types'; +import { hostActionsRouteDefinition } from './host_actions_route'; +import { getAgentDetailsRouteDefinition } from './get_agent_details_route'; +import { getAgentOnlineStatusRouteDefinition } from './get_agent_online_status_route'; + +export const getCrowdstrikeRouteDefinitions = (): EmulatorServerRouteDefinition[] => { + return [ + getTokenRouteDefinition(), + hostActionsRouteDefinition(), + getAgentDetailsRouteDefinition(), + getAgentOnlineStatusRouteDefinition(), + ]; +}; diff --git a/x-pack/packages/kbn-elastic-assistant-common/impl/mock/mock_action_response/index.ts b/x-pack/plugins/security_solution/scripts/endpoint/api_emulator/emulator_plugins/crowdstrike/routes/utils.ts similarity index 58% rename from x-pack/packages/kbn-elastic-assistant-common/impl/mock/mock_action_response/index.ts rename to x-pack/plugins/security_solution/scripts/endpoint/api_emulator/emulator_plugins/crowdstrike/routes/utils.ts index dbc095a334cea..ab8ed1ecd57b6 100644 --- a/x-pack/packages/kbn-elastic-assistant-common/impl/mock/mock_action_response/index.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/api_emulator/emulator_plugins/crowdstrike/routes/utils.ts @@ -4,8 +4,10 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +export const buildCrowdstrikeRoutePath = (path: string): string => { + if (!path.startsWith('/')) { + throw new Error(`'path' must start with '/'!`); + } -export const mockActionResponse = { - message: 'Yes, your name is Andrew. How can I assist you further, Andrew?', - usage: { prompt_tokens: 4, completion_tokens: 10, total_tokens: 14 }, + return path; }; diff --git a/x-pack/plugins/security_solution/scripts/endpoint/api_emulator/index.ts b/x-pack/plugins/security_solution/scripts/endpoint/api_emulator/index.ts index 15a48654f2963..8c4d0eae4e5e7 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/api_emulator/index.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/api_emulator/index.ts @@ -79,7 +79,6 @@ const cliRunner: RunFn = async (cliContext) => { elasticsearchUrl, asSuperuser, log, - noCertForSsl: true, }); const coreServices: ExternalEdrServerEmulatorCoreServices = { diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/fleet_server/fleet_server_services.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/fleet_server/fleet_server_services.ts index 73cf96b5b6864..1eefe220c0d39 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/common/fleet_server/fleet_server_services.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/fleet_server/fleet_server_services.ts @@ -683,24 +683,32 @@ export const isFleetServerRunning = async ( const url = new URL(fleetServerUrl); url.pathname = '/api/status'; - return axios - .request({ - method: 'GET', - url: url.toString(), - responseType: 'json', - // Custom agent to ensure we don't get cert errors - httpsAgent: new https.Agent({ rejectUnauthorized: false }), - }) - .then((response) => { - log.debug(`Fleet server is up and running at [${fleetServerUrl}]. Status: `, response.data); - return true; - }) - .catch(catchAxiosErrorFormatAndThrow) - .catch((e) => { - log.debug(`Fleet server not up at [${fleetServerUrl}]`); - log.verbose(`Call to [${url.toString()}] failed with:`, e); - return false; - }); + return pRetry( + async () => { + return axios + .request({ + method: 'GET', + url: url.toString(), + responseType: 'json', + // Custom agent to ensure we don't get cert errors + httpsAgent: new https.Agent({ rejectUnauthorized: false }), + }) + .then((response) => { + log.debug( + `Fleet server is up and running at [${fleetServerUrl}]. Status: `, + response.data + ); + return true; + }) + .catch(catchAxiosErrorFormatAndThrow) + .catch((e) => { + log.debug(`Fleet server not up at [${fleetServerUrl}]`); + log.verbose(`Call to [${url.toString()}] failed with:`, e); + return false; + }); + }, + { maxTimeout: 10000 } + ); }; /** diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/fleet_services.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/fleet_services.ts index 8d1d2f5e61f49..317cae2882e57 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/common/fleet_services.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/fleet_services.ts @@ -58,10 +58,10 @@ import type { PostAgentUnenrollResponse, CopyAgentPolicyRequest, } from '@kbn/fleet-plugin/common/types'; -import nodeFetch from 'node-fetch'; import semver from 'semver'; import axios from 'axios'; import { userInfo } from 'os'; +import pRetry from 'p-retry'; import { isFleetServerRunning } from './fleet_server/fleet_server_services'; import { getEndpointPackageInfo } from '../../../common/endpoint/utils/package'; import type { DownloadAndStoreAgentResponse } from './agent_downloads_service'; @@ -79,6 +79,7 @@ import { FleetAgentGenerator } from '../../../common/endpoint/data_generators/fl const fleetGenerator = new FleetAgentGenerator(); const CURRENT_USERNAME = userInfo().username.toLowerCase(); const DEFAULT_AGENT_POLICY_NAME = `${CURRENT_USERNAME} test policy`; + /** A Fleet agent policy that includes integrations that don't actually require an agent to run on a host. Example: SenttinelOne */ export const DEFAULT_AGENTLESS_INTEGRATIONS_AGENT_POLICY_NAME = `${CURRENT_USERNAME} - agentless integrations`; @@ -411,14 +412,20 @@ export const getAgentVersionMatchingCurrentStack = async ( ); } - const agentVersions = await axios - .get('https://artifacts-api.elastic.co/v1/versions') - .then((response) => - map( - response.data.versions.filter(isValidArtifactVersion), - (version) => version.split('-SNAPSHOT')[0] - ) - ); + const agentVersions = await pRetry( + async () => { + return axios + .get('https://artifacts-api.elastic.co/v1/versions') + .catch(catchAxiosErrorFormatAndThrow) + .then((response) => + map( + response.data.versions.filter(isValidArtifactVersion), + (version) => version.split('-SNAPSHOT')[0] + ) + ); + }, + { maxTimeout: 10000 } + ); let version = semver.maxSatisfying(agentVersions, `<=${kbnStatus.version.number}`) ?? @@ -492,16 +499,16 @@ export const getAgentDownloadUrl = async ( log?.verbose(`Retrieving elastic agent download URL from:\n ${artifactSearchUrl}`); - const searchResult: ElasticArtifactSearchResponse = await nodeFetch(artifactSearchUrl).then( - (response) => { - if (!response.ok) { - throw new Error( - `Failed to search elastic's artifact repository: ${response.statusText} (HTTP ${response.status}) {URL: ${artifactSearchUrl})` - ); - } - - return response.json(); - } + const searchResult: ElasticArtifactSearchResponse = await pRetry( + async () => { + return axios + .get(artifactSearchUrl) + .catch(catchAxiosErrorFormatAndThrow) + .then((response) => { + return response.data; + }); + }, + { maxTimeout: 10000 } ); log?.verbose(searchResult); @@ -547,16 +554,16 @@ export const getLatestAgentDownloadVersion = async ( ): Promise => { const artifactsUrl = 'https://artifacts-api.elastic.co/v1/versions'; const semverMatch = `<=${version.replace(`-SNAPSHOT`, '')}`; - const artifactVersionsResponse: { versions: string[] } = await nodeFetch(artifactsUrl).then( - (response) => { - if (!response.ok) { - throw new Error( - `Failed to retrieve list of versions from elastic's artifact repository: ${response.statusText} (HTTP ${response.status}) {URL: ${artifactsUrl})` - ); - } - - return response.json(); - } + const artifactVersionsResponse: { versions: string[] } = await pRetry( + async () => { + return axios + .get<{ versions: string[] }>(artifactsUrl) + .catch(catchAxiosErrorFormatAndThrow) + .then((response) => { + return response.data; + }); + }, + { maxTimeout: 10000 } ); const stackVersionToArtifactVersion: Record = artifactVersionsResponse.versions diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/roles_users/endpoint_operations_analyst.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/roles_users/endpoint_operations_analyst.ts index 6880282f83876..a1f3585ffcdc7 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/common/roles_users/endpoint_operations_analyst.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/roles_users/endpoint_operations_analyst.ts @@ -71,6 +71,7 @@ export const getEndpointOperationsAnalyst: () => Omit = () => { 'actions_log_management_all', 'file_operations_all', 'execute_operations_all', + 'scan_operations_all', ], }, spaces: ['*'], diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/roles_users/serverless/es_serverless_resources/roles.yml b/x-pack/plugins/security_solution/scripts/endpoint/common/roles_users/serverless/es_serverless_resources/roles.yml index 8d469904160cd..3bc3320b96026 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/common/roles_users/serverless/es_serverless_resources/roles.yml +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/roles_users/serverless/es_serverless_resources/roles.yml @@ -493,6 +493,7 @@ soc_manager: - feature_siem.actions_log_management_all - feature_siem.file_operations_all - feature_siem.execute_operations_all + - feature_siem.scan_operations_all - feature_securitySolutionCases.all - feature_securitySolutionAssistant.all - feature_actions.all @@ -675,6 +676,7 @@ endpoint_operations_analyst: - feature_siem.actions_log_management_all # Response History - feature_siem.file_operations_all - feature_siem.execute_operations_all # Execute + - feature_siem.scan_operations_all - feature_securitySolutionCases.all - feature_securitySolutionAssistant.all - feature_actions.all @@ -753,4 +755,4 @@ endpoint_policy_manager: - feature_graph.all - feature_maps.all - feature_visualize.all - resources: "*" \ No newline at end of file + resources: "*" diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/roles_users/with_response_actions_role.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/roles_users/with_response_actions_role.ts index 0fed92037e07f..7108f0181b868 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/common/roles_users/with_response_actions_role.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/roles_users/with_response_actions_role.ts @@ -21,6 +21,7 @@ export const getWithResponseActionsRole: () => Omit = () => { ...noResponseActionsRole.kibana[0].feature.siem, 'file_operations_all', 'execute_operations_all', + 'scan_operations_all', 'host_isolation_all', 'process_operations_all', 'actions_log_management_all', diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/stack_services.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/stack_services.ts index a7dc1b7ecfe39..5d321ec09cc48 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/common/stack_services.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/stack_services.ts @@ -70,7 +70,7 @@ interface CreateRuntimeServicesOptions { log?: ToolingLog; asSuperuser?: boolean; /** If true, then a certificate will not be used when creating the Kbn/Es clients when url is `https` */ - noCertForSsl?: boolean; + useCertForSsl?: boolean; } class KbnClientExtended extends KbnClient { @@ -112,7 +112,7 @@ export const createRuntimeServices = async ({ esPassword: _esPassword, log = createToolingLogger(), asSuperuser = false, - noCertForSsl, + useCertForSsl = false, }: CreateRuntimeServicesOptions): Promise => { let username = _username; let password = _password; @@ -124,7 +124,7 @@ export const createRuntimeServices = async ({ url: kibanaUrl, username, password, - noCertForSsl, + useCertForSsl, log, }); @@ -149,7 +149,7 @@ export const createRuntimeServices = async ({ username: esUsername ?? username, password: esPassword ?? password, log, - noCertForSsl, + useCertForSsl, }) ); @@ -166,14 +166,14 @@ export const createRuntimeServices = async ({ const fleetURL = new URL(fleetServerUrl); return { - kbnClient: createKbnClient({ log, url: kibanaUrl, username, password, apiKey, noCertForSsl }), + kbnClient: createKbnClient({ log, url: kibanaUrl, username, password, apiKey, useCertForSsl }), esClient: createEsClient({ log, url: elasticsearchUrl, username: esUsername ?? username, password: esPassword ?? password, apiKey, - noCertForSsl, + useCertForSsl, }), log, localhostRealIp: getLocalhostRealIp(), @@ -222,7 +222,7 @@ export const createEsClient = ({ password, apiKey, log, - noCertForSsl, + useCertForSsl = false, }: { url: string; username: string; @@ -230,14 +230,14 @@ export const createEsClient = ({ /** If defined, both `username` and `password` will be ignored */ apiKey?: string; log?: ToolingLog; - noCertForSsl?: boolean; + useCertForSsl?: boolean; }): Client => { const isHttps = new URL(url).protocol.startsWith('https'); const clientOptions: ClientOptions = { node: buildUrlWithCredentials(url, apiKey ? '' : username, apiKey ? '' : password), }; - if (isHttps && !noCertForSsl) { + if (isHttps && useCertForSsl) { clientOptions.tls = { ca: [CA_CERTIFICATE], }; @@ -265,7 +265,7 @@ export const createKbnClient = ({ password, apiKey, log = createToolingLogger(), - noCertForSsl, + useCertForSsl = false, }: { url: string; username: string; @@ -273,7 +273,7 @@ export const createKbnClient = ({ /** If defined, both `username` and `password` will be ignored */ apiKey?: string; log?: ToolingLog; - noCertForSsl?: boolean; + useCertForSsl?: boolean; }): KbnClient => { const isHttps = new URL(url).protocol.startsWith('https'); const clientOptions: ConstructorParameters[0] = { @@ -282,7 +282,7 @@ export const createKbnClient = ({ url: buildUrlWithCredentials(url, username, password), }; - if (isHttps && !noCertForSsl) { + if (isHttps && useCertForSsl) { clientOptions.certificateAuthorities = [CA_CERTIFICATE]; } diff --git a/x-pack/plugins/security_solution/scripts/endpoint/env_data_loader/index.ts b/x-pack/plugins/security_solution/scripts/endpoint/env_data_loader/index.ts index 4de4929b8c4c2..031541e8f5403 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/env_data_loader/index.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/env_data_loader/index.ts @@ -22,7 +22,6 @@ export const cli = () => { url: cliContext.flags.kibana as string, username: cliContext.flags.username as string, password: cliContext.flags.password as string, - noCertForSsl: true, }); const options = { diff --git a/x-pack/plugins/security_solution/scripts/endpoint/sentinelone_host/common.ts b/x-pack/plugins/security_solution/scripts/endpoint/sentinelone_host/common.ts index 3bce0126fbf29..d508f9bc605bf 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/sentinelone_host/common.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/sentinelone_host/common.ts @@ -10,6 +10,7 @@ import type { AxiosRequestConfig } from 'axios'; import axios from 'axios'; import type { KbnClient } from '@kbn/test'; import { SENTINELONE_CONNECTOR_ID } from '@kbn/stack-connectors-plugin/common/sentinelone/constants'; +import pRetry from 'p-retry'; import { dump } from '../common/utils'; import { type RuleResponse } from '../../../common/api/detection_engine'; import { createToolingLogger } from '../../../common/endpoint/data_loaders/utils'; @@ -86,13 +87,18 @@ export class S1Client { this.log.debug(`Request: `, requestOptions); - return axios - .request(requestOptions) - .then((response) => { - this.log.verbose(`Response: `, response); - return response.data; - }) - .catch(catchAxiosErrorFormatAndThrow); + return pRetry( + async () => { + return axios + .request(requestOptions) + .then((response) => { + this.log.verbose(`Response: `, response); + return response.data; + }) + .catch(catchAxiosErrorFormatAndThrow); + }, + { maxTimeout: 10000 } + ); } public buildUrl(path: string): string { diff --git a/x-pack/plugins/security_solution/scripts/endpoint/sentinelone_host/index.ts b/x-pack/plugins/security_solution/scripts/endpoint/sentinelone_host/index.ts index 2c179f6e853ab..d2f4190821413 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/sentinelone_host/index.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/sentinelone_host/index.ts @@ -111,7 +111,6 @@ const runCli: RunFn = async ({ log, flags }) => { url: kibanaUrl, username, password, - noCertForSsl: true, }); const runningS1VMs = ( diff --git a/x-pack/plugins/security_solution/server/assistant/tools/alert_counts/alert_counts_tool.ts b/x-pack/plugins/security_solution/server/assistant/tools/alert_counts/alert_counts_tool.ts index 1699d68a2f314..ed29985b48fe8 100644 --- a/x-pack/plugins/security_solution/server/assistant/tools/alert_counts/alert_counts_tool.ts +++ b/x-pack/plugins/security_solution/server/assistant/tools/alert_counts/alert_counts_tool.ts @@ -6,8 +6,8 @@ */ import type { SearchResponse } from '@elastic/elasticsearch/lib/api/types'; -import { DynamicTool } from '@langchain/core/tools'; - +import { DynamicStructuredTool } from '@langchain/core/tools'; +import { z } from 'zod'; import { requestHasRequiredAnonymizationParams } from '@kbn/elastic-assistant-plugin/server/lib/langchain/helpers'; import type { AssistantTool, AssistantToolParams } from '@kbn/elastic-assistant-plugin/server'; import { getAlertsCountQuery } from './get_alert_counts_query'; @@ -17,7 +17,7 @@ export interface AlertCountsToolParams extends AssistantToolParams { alertsIndexPattern: string; } export const ALERT_COUNTS_TOOL_DESCRIPTION = - 'Call this for the counts of last 24 hours of open and acknowledged alerts in the environment, grouped by their severity and workflow status.'; + 'Call this for the counts of last 24 hours of open and acknowledged alerts in the environment, grouped by their severity and workflow status. The response will be JSON and from it you can summarize the information to answer the question.'; export const ALERT_COUNTS_TOOL: AssistantTool = { id: 'alert-counts-tool', @@ -31,9 +31,10 @@ export const ALERT_COUNTS_TOOL: AssistantTool = { getTool(params: AssistantToolParams) { if (!this.isSupported(params)) return null; const { alertsIndexPattern, esClient } = params as AlertCountsToolParams; - return new DynamicTool({ + return new DynamicStructuredTool({ name: 'AlertCountsTool', description: ALERT_COUNTS_TOOL_DESCRIPTION, + schema: z.object({}), func: async () => { const query = getAlertsCountQuery(alertsIndexPattern); const result = await esClient.search(query); diff --git a/x-pack/plugins/security_solution/server/assistant/tools/attack_discovery/attack_discovery_tool.test.ts b/x-pack/plugins/security_solution/server/assistant/tools/attack_discovery/attack_discovery_tool.test.ts index bd67b00257721..a608673adf661 100644 --- a/x-pack/plugins/security_solution/server/assistant/tools/attack_discovery/attack_discovery_tool.test.ts +++ b/x-pack/plugins/security_solution/server/assistant/tools/attack_discovery/attack_discovery_tool.test.ts @@ -8,7 +8,7 @@ import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import type { KibanaRequest } from '@kbn/core-http-server'; import type { AttackDiscoveryPostRequestBody } from '@kbn/elastic-assistant-common'; -import type { ActionsClientLlm } from '@kbn/elastic-assistant-common/impl/language_models'; +import type { ActionsClientLlm } from '@kbn/langchain/server'; import type { DynamicTool } from '@langchain/core/tools'; import { ATTACK_DISCOVERY_TOOL } from './attack_discovery_tool'; diff --git a/x-pack/plugins/security_solution/server/assistant/tools/esql_language_knowledge_base/esql_language_knowledge_base_structured_tool.ts b/x-pack/plugins/security_solution/server/assistant/tools/esql_language_knowledge_base/esql_language_knowledge_base_structured_tool.ts deleted file mode 100644 index 773528b8e785a..0000000000000 --- a/x-pack/plugins/security_solution/server/assistant/tools/esql_language_knowledge_base/esql_language_knowledge_base_structured_tool.ts +++ /dev/null @@ -1,52 +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 { DynamicStructuredTool } from '@langchain/core/tools'; -import { z } from 'zod'; -import type { AssistantTool, AssistantToolParams } from '@kbn/elastic-assistant-plugin/server'; -import { APP_UI_ID } from '../../../../common'; - -export type EsqlKnowledgeBaseToolParams = AssistantToolParams; - -const toolDetails = { - description: - 'Call this for knowledge on how to build an ESQL query, or answer questions about the ES|QL query language. Input must always be the query on a single line, with no other text. Only output valid ES|QL queries as described above. Do not add any additional text to describe your output.', - id: 'esql-knowledge-base-structured-tool', - name: 'ESQLKnowledgeBaseStructuredTool', -}; -export const ESQL_KNOWLEDGE_BASE_STRUCTURED_TOOL: AssistantTool = { - ...toolDetails, - sourceRegister: APP_UI_ID, - isSupported: (params: AssistantToolParams): params is EsqlKnowledgeBaseToolParams => { - const { chain, isEnabledKnowledgeBase, modelExists } = params; - return isEnabledKnowledgeBase && modelExists && chain != null; - }, - getTool(params: AssistantToolParams) { - if (!this.isSupported(params)) return null; - - const { chain } = params as EsqlKnowledgeBaseToolParams; - if (chain == null) return null; - - return new DynamicStructuredTool({ - name: toolDetails.name, - description: toolDetails.description, - schema: z.object({ - question: z.string().describe(`The user's exact question about ESQL`), - }), - func: async (input, _, cbManager) => { - const result = await chain.invoke( - { - query: input.question, - }, - cbManager - ); - return result.text; - }, - tags: ['esql', 'query-generation', 'knowledge-base'], - }); - }, -}; diff --git a/x-pack/plugins/security_solution/server/assistant/tools/esql_language_knowledge_base/esql_language_knowledge_base_tool.ts b/x-pack/plugins/security_solution/server/assistant/tools/esql_language_knowledge_base/esql_language_knowledge_base_tool.ts index 567182d042339..692753a22dea0 100644 --- a/x-pack/plugins/security_solution/server/assistant/tools/esql_language_knowledge_base/esql_language_knowledge_base_tool.ts +++ b/x-pack/plugins/security_solution/server/assistant/tools/esql_language_knowledge_base/esql_language_knowledge_base_tool.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { DynamicTool } from '@langchain/core/tools'; +import { DynamicStructuredTool } from '@langchain/core/tools'; +import { z } from 'zod'; import type { AssistantTool, AssistantToolParams } from '@kbn/elastic-assistant-plugin/server'; import { APP_UI_ID } from '../../../../common'; @@ -30,13 +31,16 @@ export const ESQL_KNOWLEDGE_BASE_TOOL: AssistantTool = { const { chain } = params as EsqlKnowledgeBaseToolParams; if (chain == null) return null; - return new DynamicTool({ + return new DynamicStructuredTool({ name: toolDetails.name, description: toolDetails.description, + schema: z.object({ + question: z.string().describe(`The user's exact question about ESQL`), + }), func: async (input, _, cbManager) => { const result = await chain.invoke( { - query: input, + query: input.question, }, cbManager ); diff --git a/x-pack/plugins/security_solution/server/assistant/tools/index.ts b/x-pack/plugins/security_solution/server/assistant/tools/index.ts index 66b5f458a8181..b99c1f6e0cd38 100644 --- a/x-pack/plugins/security_solution/server/assistant/tools/index.ts +++ b/x-pack/plugins/security_solution/server/assistant/tools/index.ts @@ -9,7 +9,6 @@ import type { AssistantTool } from '@kbn/elastic-assistant-plugin/server'; import { ALERT_COUNTS_TOOL } from './alert_counts/alert_counts_tool'; import { ESQL_KNOWLEDGE_BASE_TOOL } from './esql_language_knowledge_base/esql_language_knowledge_base_tool'; -import { ESQL_KNOWLEDGE_BASE_STRUCTURED_TOOL } from './esql_language_knowledge_base/esql_language_knowledge_base_structured_tool'; import { OPEN_AND_ACKNOWLEDGED_ALERTS_TOOL } from './open_and_acknowledged_alerts/open_and_acknowledged_alerts_tool'; import { ATTACK_DISCOVERY_TOOL } from './attack_discovery/attack_discovery_tool'; @@ -17,6 +16,5 @@ export const getAssistantTools = (): AssistantTool[] => [ ALERT_COUNTS_TOOL, ATTACK_DISCOVERY_TOOL, ESQL_KNOWLEDGE_BASE_TOOL, - ESQL_KNOWLEDGE_BASE_STRUCTURED_TOOL, OPEN_AND_ACKNOWLEDGED_ALERTS_TOOL, ]; diff --git a/x-pack/plugins/security_solution/server/assistant/tools/open_and_acknowledged_alerts/open_and_acknowledged_alerts_tool.ts b/x-pack/plugins/security_solution/server/assistant/tools/open_and_acknowledged_alerts/open_and_acknowledged_alerts_tool.ts index f77d920978756..ed6f65ffb7610 100644 --- a/x-pack/plugins/security_solution/server/assistant/tools/open_and_acknowledged_alerts/open_and_acknowledged_alerts_tool.ts +++ b/x-pack/plugins/security_solution/server/assistant/tools/open_and_acknowledged_alerts/open_and_acknowledged_alerts_tool.ts @@ -8,9 +8,9 @@ import type { SearchResponse } from '@elastic/elasticsearch/lib/api/types'; import type { Replacements } from '@kbn/elastic-assistant-common'; import { getAnonymizedValue, transformRawData } from '@kbn/elastic-assistant-common'; -import { DynamicTool } from '@langchain/core/tools'; +import { DynamicStructuredTool } from '@langchain/core/tools'; import { requestHasRequiredAnonymizationParams } from '@kbn/elastic-assistant-plugin/server/lib/langchain/helpers'; - +import { z } from 'zod'; import type { AssistantTool, AssistantToolParams } from '@kbn/elastic-assistant-plugin/server'; import { getOpenAndAcknowledgedAlertsQuery } from './get_open_and_acknowledged_alerts_query'; import { getRawDataOrDefault, sizeIsOutOfRange } from './helpers'; @@ -22,7 +22,7 @@ export interface OpenAndAcknowledgedAlertsToolParams extends AssistantToolParams } export const OPEN_AND_ACKNOWLEDGED_ALERTS_TOOL_DESCRIPTION = - 'Call this for knowledge about the latest n open and acknowledged alerts (sorted by `kibana.alert.risk_score`) in the environment, or when answering questions about open alerts. Input should be a string.'; + 'Call this for knowledge about the latest n open and acknowledged alerts (sorted by `kibana.alert.risk_score`) in the environment, or when answering questions about open alerts. Do not call this tool for alert count or quantity. Input should be an empty object. The output is an array of the latest n open and acknowledged alerts.'; /** * Returns a tool for querying open and acknowledged alerts, or null if the @@ -53,9 +53,10 @@ export const OPEN_AND_ACKNOWLEDGED_ALERTS_TOOL: AssistantTool = { replacements, size, } = params as OpenAndAcknowledgedAlertsToolParams; - return new DynamicTool({ + return new DynamicStructuredTool({ name: 'OpenAndAcknowledgedAlertsTool', description: OPEN_AND_ACKNOWLEDGED_ALERTS_TOOL_DESCRIPTION, + schema: z.object({}), func: async () => { const query = getOpenAndAcknowledgedAlertsQuery({ alertsIndexPattern, diff --git a/x-pack/plugins/security_solution/server/config.ts b/x-pack/plugins/security_solution/server/config.ts index 19e8afe176c9a..3bfcf13a9104a 100644 --- a/x-pack/plugins/security_solution/server/config.ts +++ b/x-pack/plugins/security_solution/server/config.ts @@ -128,7 +128,7 @@ export const configSchema = schema.object({ * Complete External Response Actions task: Timeout value for how long the task should run */ completeExternalResponseActionsTaskTimeout: schema.string({ - defaultValue: '20m', + defaultValue: '5m', validate: isValidTaskManagerDuration, }), diff --git a/x-pack/plugins/security_solution/server/endpoint/lib/response_actions/complete_external_actions_task.ts b/x-pack/plugins/security_solution/server/endpoint/lib/response_actions/complete_external_actions_task.ts index 8d77ddecbcf56..fd823928b6631 100644 --- a/x-pack/plugins/security_solution/server/endpoint/lib/response_actions/complete_external_actions_task.ts +++ b/x-pack/plugins/security_solution/server/endpoint/lib/response_actions/complete_external_actions_task.ts @@ -41,7 +41,7 @@ export class CompleteExternalResponseActionsTask { private log: Logger; private esClient: ElasticsearchClient | undefined = undefined; private cleanup: (() => void) | undefined; - private taskTimeout = '20m'; // Default. Real value comes from server config + private taskTimeout = '5m'; // Default. Real value comes from server config private taskInterval = '60s'; // Default. Real value comes from server config constructor(protected readonly options: CompleteExternalResponseActionsTaskConstructorOptions) { diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/agent/agent_status_handler.ts b/x-pack/plugins/security_solution/server/endpoint/routes/agent/agent_status_handler.ts index 231eb3cccaf05..25f281facb848 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/agent/agent_status_handler.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/agent/agent_status_handler.ts @@ -6,7 +6,7 @@ */ import type { RequestHandler } from '@kbn/core/server'; -import { getAgentStatus } from '../../services/agent/agent_status'; +import { getSentinelOneAgentStatus } from '../../services/agent/agent_status'; import { errorHandler } from '../error_handler'; import type { EndpointAgentStatusRequestQueryParams } from '../../../../common/api/endpoint/agent/get_agent_status_route'; import { EndpointAgentStatusRequestSchema } from '../../../../common/api/endpoint/agent/get_agent_status_route'; @@ -63,8 +63,10 @@ export const getAgentStatusRouteHandler = ( // `getter` function), we need to include this additional validation here, since // `agent_type` is included in the schema independent of the feature flag if ( - agentType === 'sentinel_one' && - !endpointContext.experimentalFeatures.responseActionsSentinelOneV1Enabled + (agentType === 'sentinel_one' && + !endpointContext.experimentalFeatures.responseActionsSentinelOneV1Enabled) || + (agentType === 'crowdstrike' && + !endpointContext.experimentalFeatures.responseActionsCrowdstrikeManualHostIsolationEnabled) ) { return errorHandler( logger, @@ -79,17 +81,21 @@ export const getAgentStatusRouteHandler = ( esClient, soClient, endpointService: endpointContext.service, + connectorActionsClient: + agentType === 'crowdstrike' ? (await context.actions).getActionsClient() : undefined, }); // 8.15: use the new `agentStatusClientEnabled` FF enabled - const getAgentStatusPromise = endpointContext.experimentalFeatures.agentStatusClientEnabled - ? agentStatusClient.getAgentStatuses(agentIds) - : getAgentStatus({ + const data = endpointContext.experimentalFeatures.agentStatusClientEnabled + ? await agentStatusClient.getAgentStatuses(agentIds) + : agentType === 'sentinel_one' + ? await getSentinelOneAgentStatus({ agentType, agentIds, logger, connectorActionsClient: (await context.actions).getActionsClient(), - }); + }) + : []; logger.debug( `Retrieving status for: agentType [${agentType}], agentIds: [${agentIds.join(', ')}]` @@ -98,7 +104,7 @@ export const getAgentStatusRouteHandler = ( try { return response.ok({ body: { - data: await getAgentStatusPromise, + data, }, }); } catch (e) { diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/crowdstrike/mocks.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/crowdstrike/mocks.ts index e24eedb7ddf57..8ee3dcd51aeda 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/crowdstrike/mocks.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/clients/crowdstrike/mocks.ts @@ -5,14 +5,17 @@ * 2.0. */ -import type { CrowdstrikeGetAgentsResponse } from '@kbn/stack-connectors-plugin/common/crowdstrike/types'; import { CROWDSTRIKE_CONNECTOR_ID, SUB_ACTION, } from '@kbn/stack-connectors-plugin/common/crowdstrike/constants'; 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 { + createCrowdstrikeAgentDetailsMock, + createCrowdstrikeGetAgentOnlineStatusDetailsMock, + createCrowdstrikeGetAgentsApiResponseMock, +} from '../../../../../../scripts/endpoint/api_emulator/emulator_plugins/crowdstrike/mocks'; import type { ResponseActionsClientOptionsMock } from '../mocks'; import { responseActionsClientMock } from '../mocks'; import type { NormalizedExternalConnectorClient } from '../../..'; @@ -21,130 +24,6 @@ export interface CrowdstrikeActionsClientOptionsMock extends ResponseActionsClie connectorActions: NormalizedExternalConnectorClient; } -const createCrowdstrikeAgentDetailsMock = ( - overrides: Partial = {} -): CrowdstrikeGetAgentsResponse['resources'][number][number] => { - return merge( - { - device_id: '123456789', - cid: '234567890', - agent_load_flags: '0', - agent_local_time: '2024-03-18T22:21:00.173Z', - agent_version: '7.07.16206.0', - bios_manufacturer: 'Amazon EC2', - bios_version: '1.0', - config_id_base: '65994753', - config_id_build: '16206', - config_id_platform: '8', - cpu_signature: '8392466', - cpu_vendor: '1', - external_ip: '18.157.150.216', - mac_address: '03-f4-f4-f4-f4', - instance_id: 'i-456789', - service_provider: 'AWS_EC2_V2', - service_provider_account_id: '23456789', - hostname: 'Crowdstrike-1460', - first_seen: '2024-03-15T13:18:56Z', - last_login_timestamp: '2024-03-15T22:11:47Z', - last_login_user: 'testuser', - last_login_uid: '1002', - last_seen: '2024-03-20T07:19:01Z', - local_ip: '172.31.200.45', - major_version: '5', - minor_version: '14', - os_version: 'RHEL 9.3', - platform_id: '3', - platform_name: 'Linux', - policies: [ - { - policy_type: 'prevention', - policy_id: '234234234234', - applied: true, - settings_hash: 'f0e04444', - assigned_date: '2024-03-15T13:20:02.25821602Z', - applied_date: '2024-03-15T13:20:16.804783955Z', - rule_groups: [], - }, - ], - reduced_functionality_mode: 'no', - device_policies: { - prevention: { - policy_type: 'prevention', - policy_id: '234234234234', - applied: true, - settings_hash: 'f0e04444', - assigned_date: '2024-03-15T13:20:02.25821602Z', - applied_date: '2024-03-15T13:20:16.804783955Z', - rule_groups: [], - }, - sensor_update: { - policy_type: 'sensor-update', - policy_id: '234234234234', - applied: true, - settings_hash: 'tagged|5;', - assigned_date: '2024-03-15T13:20:02.258765734Z', - applied_date: '2024-03-15T13:23:53.773752711Z', - uninstall_protection: 'UNKNOWN', - }, - global_config: { - policy_type: 'globalconfig', - policy_id: '234234234234', - applied: true, - settings_hash: 'f0e04444', - assigned_date: '2024-03-18T22:21:01.50638371Z', - applied_date: '2024-03-18T22:21:30.565040189Z', - }, - remote_response: { - policy_type: 'remote-response', - policy_id: '234234234234', - applied: true, - settings_hash: 'f0e04444', - assigned_date: '2024-03-15T13:20:02.258285018Z', - applied_date: '2024-03-15T13:20:17.016591803Z', - }, - }, - groups: [], - group_hash: '45678909876545678', - product_type_desc: 'Server', - provision_status: 'NotProvisioned', - serial_number: '345678765-35d6-e704-1723-423423432', - status: 'normal', - system_manufacturer: 'Amazon EC2', - system_product_name: 't3a.medium', - tags: [], - modified_timestamp: '2024-03-20T07:19:45Z', - meta: { - version: '484', - version_string: '9:33384301139', - }, - zone_group: 'eu-central-1a', - kernel_version: '5.14.0-234234el9_3.x86_64', - chassis_type: '1', - chassis_type_desc: 'Other', - connection_ip: '172.31.200.45', - default_gateway_ip: '172.31.200.1', - connection_mac_address: '02-e8-f1-0e-b7-c4', - linux_sensor_mode: 'Kernel Mode', - deployment_type: 'Standard', - }, - overrides - ); -}; - -const createCrowdstrikeGetAgentsApiResponseMock = ( - data: CrowdstrikeGetAgentsResponse['resources'][number] = [createCrowdstrikeAgentDetailsMock()] -): CrowdstrikeGetAgentsResponse => { - return { - meta: { - query_time: 0.001831479, - powered_by: 'device-api', - trace_id: '4567898765-432423432432-42342342', - }, - errors: null, - resources: [data], - }; -}; - const createConnectorActionsClientMock = (): ActionsClientMock => { const client = responseActionsClientMock.createConnectorActionsClient(); @@ -167,7 +46,9 @@ const createConnectorActionsClientMock = (): ActionsClientMock => { switch (subAction) { case SUB_ACTION.GET_AGENT_DETAILS: return responseActionsClientMock.createConnectorActionExecuteResponse({ - data: createCrowdstrikeGetAgentsApiResponseMock(), + data: createCrowdstrikeGetAgentsApiResponseMock([ + createCrowdstrikeAgentDetailsMock({}), + ]), }); default: @@ -224,6 +105,7 @@ const createEventSearchResponseMock = (): CrowdstrikeEventSearchResponseMock => export const CrowdstrikeMock = { createGetAgentsResponse: createCrowdstrikeGetAgentsApiResponseMock, + createGetAgentOnlineStatusDetails: createCrowdstrikeGetAgentOnlineStatusDetailsMock, createCrowdstrikeAgentDetails: createCrowdstrikeAgentDetailsMock, createConnectorActionsClient: createConnectorActionsClientMock, createConstructorOptions: createConstructorOptionsMock, 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 6fbcb6ff3350b..df326a269f0a3 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 @@ -106,6 +106,9 @@ describe('SentinelOneActionsClient class', () => { }); it('should write action request and response to endpoint indexes when `responseActionsSentinelOneV2Enabled` FF is Disabled', async () => { + // @ts-expect-error updating readonly attribute + classConstructorOptions.endpointService.experimentalFeatures.responseActionsSentinelOneV2Enabled = + false; await s1ActionsClient.isolate(createS1IsolationOptions()); expect(classConstructorOptions.esClient.index).toHaveBeenCalledTimes(2); @@ -237,6 +240,9 @@ describe('SentinelOneActionsClient class', () => { }); it('should write action request and response to endpoint indexes when `responseActionsSentinelOneV2Enabled` is Disabled', async () => { + // @ts-expect-error updating readonly attribute + classConstructorOptions.endpointService.experimentalFeatures.responseActionsSentinelOneV2Enabled = + false; await s1ActionsClient.release(createS1IsolationOptions()); expect(classConstructorOptions.esClient.index).toHaveBeenCalledTimes(2); diff --git a/x-pack/plugins/security_solution/server/endpoint/services/agent/agent_status.test.ts b/x-pack/plugins/security_solution/server/endpoint/services/agent/agent_status.test.ts index 2f89b218f51e9..d0cbb85001637 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/agent/agent_status.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/agent/agent_status.test.ts @@ -6,7 +6,7 @@ */ import type { GetAgentStatusOptions } from './agent_status'; -import { getAgentStatus, SENTINEL_ONE_NETWORK_STATUS } from './agent_status'; +import { getSentinelOneAgentStatus, SENTINEL_ONE_NETWORK_STATUS } from './agent_status'; import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { sentinelOneMock } from '../actions/clients/sentinelone/mocks'; import { responseActionsClientMock } from '../actions/clients/mocks'; @@ -18,7 +18,7 @@ describe('Endpoint Get Agent Status service', () => { agentStatusOptions = { agentType: 'sentinel_one', agentIds: ['1', '2'], - logger: loggingSystemMock.create().get('getAgentStatus'), + logger: loggingSystemMock.create().get('getSentinelOneAgentStatus'), connectorActionsClient: sentinelOneMock.createConnectorActionsClient(), }; }); @@ -27,7 +27,7 @@ describe('Endpoint Get Agent Status service', () => { (agentStatusOptions.connectorActionsClient.getAll as jest.Mock).mockImplementation(async () => { throw new Error('boom'); }); - const getStatusResponsePromise = getAgentStatus(agentStatusOptions); + const getStatusResponsePromise = getSentinelOneAgentStatus(agentStatusOptions); await expect(getStatusResponsePromise).rejects.toHaveProperty( 'message', @@ -38,7 +38,7 @@ describe('Endpoint Get Agent Status service', () => { it('should throw error if no SentinelOne connector is registered', async () => { (agentStatusOptions.connectorActionsClient.getAll as jest.Mock).mockResolvedValue([]); - const getStatusResponsePromise = getAgentStatus(agentStatusOptions); + const getStatusResponsePromise = getSentinelOneAgentStatus(agentStatusOptions); await expect(getStatusResponsePromise).rejects.toHaveProperty( 'message', @@ -48,7 +48,7 @@ describe('Endpoint Get Agent Status service', () => { }); it('should send api request to SentinelOne', async () => { - await getAgentStatus(agentStatusOptions); + await getSentinelOneAgentStatus(agentStatusOptions); expect(agentStatusOptions.connectorActionsClient.execute).toHaveBeenCalledWith({ actionId: 's1-connector-instance-id', @@ -68,7 +68,7 @@ describe('Endpoint Get Agent Status service', () => { serviceMessage: 'boom', }) ); - const getStatusResponsePromise = getAgentStatus(agentStatusOptions); + const getStatusResponsePromise = getSentinelOneAgentStatus(agentStatusOptions); await expect(getStatusResponsePromise).rejects.toHaveProperty( 'message', @@ -98,7 +98,7 @@ describe('Endpoint Get Agent Status service', () => { }) ); - await expect(getAgentStatus(agentStatusOptions)).resolves.toEqual({ + await expect(getSentinelOneAgentStatus(agentStatusOptions)).resolves.toEqual({ aaa: { agentType: 'sentinel_one', found: true, diff --git a/x-pack/plugins/security_solution/server/endpoint/services/agent/agent_status.ts b/x-pack/plugins/security_solution/server/endpoint/services/agent/agent_status.ts index d7268bb494943..1f5141b2bb0f7 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/agent/agent_status.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/agent/agent_status.ts @@ -28,8 +28,7 @@ export interface GetAgentStatusOptions { connectorActionsClient: ActionsClient; logger: Logger; } - -export const getAgentStatus = async ({ +export const getSentinelOneAgentStatus = async ({ agentType, agentIds, connectorActionsClient, diff --git a/x-pack/plugins/security_solution/server/endpoint/services/agent/clients/crowdstrike/crowdstrike_agent_status_client.test.ts b/x-pack/plugins/security_solution/server/endpoint/services/agent/clients/crowdstrike/crowdstrike_agent_status_client.test.ts new file mode 100644 index 0000000000000..cd70ac070d115 --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/services/agent/clients/crowdstrike/crowdstrike_agent_status_client.test.ts @@ -0,0 +1,300 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { estypes } from '@elastic/elasticsearch'; +import { + CrowdstrikeAgentStatusClient, + CROWDSTRIKE_NETWORK_STATUS, + CROWDSTRIKE_STATUS_RESPONSE, +} from './crowdstrike_agent_status_client'; +import { NormalizedExternalConnectorClient } from '../../..'; +import { AgentStatusClientError } from '../errors'; +import { HostStatus } from '../../../../../../common/endpoint/types'; +import { CrowdstrikeMock } from '../../../actions/clients/crowdstrike/mocks'; +import { responseActionsClientMock } from '../../../actions/clients/mocks'; +import { savedObjectsClientMock } from '@kbn/core-saved-objects-api-server-mocks'; +import type { RawCrowdstrikeInfo } from './types'; + +jest.mock('../../..', () => ({ + NormalizedExternalConnectorClient: jest.fn(), + getPendingActionsSummary: jest.fn().mockResolvedValue([]), +})); + +const baseResponse = { + took: 1, + timed_out: false, + _shards: { total: 1, successful: 1, skipped: 0, failed: 0 }, +}; + +const getMockSearchResponse = ( + status: CROWDSTRIKE_NETWORK_STATUS, + agentName: string, + wrongAgentName?: boolean +) => ({ + ...baseResponse, + hits: { + hits: [ + { + _id: '1', + _index: 'index', + fields: { 'crowdstrike.host.id': [agentName] }, + inner_hits: { + most_recent: { + hits: { + hits: [ + { + _id: '1', + _index: 'index', + _source: { + crowdstrike: { + host: { + id: !wrongAgentName ? agentName : 'wrongAgentName', + last_seen: '2023-01-01', + status, + }, + }, + }, + }, + ], + }, + }, + }, + }, + ], + }, +}); +describe('CrowdstrikeAgentStatusClient', () => { + let client: CrowdstrikeAgentStatusClient; + const constructorOptions = responseActionsClientMock.createConstructorOptions(); + + beforeEach(() => { + client = new CrowdstrikeAgentStatusClient({ + esClient: constructorOptions.esClient, + soClient: savedObjectsClientMock.create(), + connectorActionsClient: CrowdstrikeMock.createConnectorActionsClient(), + endpointService: constructorOptions.endpointService, + }); + }); + + describe('getAgentStatusFromConnectorAction', () => { + it('should get agent status from connector action', async () => { + const agentIds = ['agent1', 'agent2']; + const mockExecute = jest.fn().mockResolvedValue({ + data: { + resources: [ + { id: 'agent1', state: CROWDSTRIKE_STATUS_RESPONSE.ONLINE }, + { id: 'agent2', state: CROWDSTRIKE_STATUS_RESPONSE.OFFLINE }, + ], + }, + }); + + (NormalizedExternalConnectorClient as jest.Mock).mockImplementation(() => ({ + setup: jest.fn(), + execute: mockExecute, + })); + + // @ts-expect-error private method + const result = await client.getAgentStatusFromConnectorAction(agentIds); + + expect(mockExecute).toHaveBeenCalledWith({ + params: { + subAction: 'getAgentOnlineStatus', + subActionParams: { + ids: agentIds, + }, + }, + }); + + expect(result).toEqual({ + agent1: { id: 'agent1', state: CROWDSTRIKE_STATUS_RESPONSE.ONLINE }, + agent2: { id: 'agent2', state: CROWDSTRIKE_STATUS_RESPONSE.OFFLINE }, + }); + }); + }); + + describe('getAgentStatuses', () => { + beforeEach(() => { + // @ts-expect-error private method + (client.getAgentStatusFromConnectorAction as Jest.Mock) = jest.fn(); + }); + afterEach(() => { + jest.clearAllMocks(); + }); + it('should return found false when there is no agent.host.id', async () => { + const agentIds = ['agent1']; + const searchResponse: estypes.SearchResponse = getMockSearchResponse( + CROWDSTRIKE_NETWORK_STATUS.NORMAL, + 'agent1', + true + ); + + constructorOptions.esClient.search.mockResolvedValueOnce(searchResponse); + + const agentStatusResponse = { + agent1: { id: 'agent1', state: CROWDSTRIKE_STATUS_RESPONSE.ONLINE }, + }; + // @ts-expect-error private method + (client.getAgentStatusFromConnectorAction as Jest.Mock).mockResolvedValue( + agentStatusResponse + ); + + const result = await client.getAgentStatuses(agentIds); + + expect(constructorOptions.esClient.search).toHaveBeenCalled(); + expect(result).toEqual({ + agent1: { + agentId: 'agent1', + agentType: 'crowdstrike', + found: false, + isolated: false, + lastSeen: '2023-01-01', + status: HostStatus.HEALTHY, + pendingActions: {}, + }, + }); + }); + it('should accept NORMAL status', async () => { + const agentIds = ['agent1']; + const searchResponse: estypes.SearchResponse = getMockSearchResponse( + CROWDSTRIKE_NETWORK_STATUS.NORMAL, + 'agent1' + ); + + constructorOptions.esClient.search.mockResolvedValueOnce(searchResponse); + + const agentStatusResponse = { + agent1: { id: 'agent1', state: CROWDSTRIKE_STATUS_RESPONSE.ONLINE }, + }; + // @ts-expect-error private method + (client.getAgentStatusFromConnectorAction as Jest.Mock).mockResolvedValue( + agentStatusResponse + ); + + const result = await client.getAgentStatuses(agentIds); + + expect(constructorOptions.esClient.search).toHaveBeenCalled(); + expect(result).toEqual({ + agent1: { + agentId: 'agent1', + agentType: 'crowdstrike', + found: true, + isolated: false, + lastSeen: '2023-01-01', + status: HostStatus.HEALTHY, + pendingActions: {}, + }, + }); + }); + + it('should accept CONTAINED STATUS ', async () => { + const agentIds = ['agent2']; + const searchResponse: estypes.SearchResponse = getMockSearchResponse( + CROWDSTRIKE_NETWORK_STATUS.CONTAINED, + 'agent2' + ); + constructorOptions.esClient.search.mockResolvedValueOnce(searchResponse); + + const agentStatusResponse = { + agent2: { id: 'agent2', state: CROWDSTRIKE_STATUS_RESPONSE.OFFLINE }, + }; + + // @ts-expect-error private method + (client.getAgentStatusFromConnectorAction as Jest.Mock).mockResolvedValue( + agentStatusResponse + ); + + const result = await client.getAgentStatuses(agentIds); + + expect(constructorOptions.esClient.search).toHaveBeenCalled(); + expect(result).toEqual({ + agent2: { + agentId: 'agent2', + agentType: 'crowdstrike', + found: true, + isolated: true, + lastSeen: '2023-01-01', + status: HostStatus.OFFLINE, + pendingActions: {}, + }, + }); + }); + it('should set isolated to false if host is pending isolate', async () => { + const agentIds = ['agent2']; + const searchResponse: estypes.SearchResponse = getMockSearchResponse( + CROWDSTRIKE_NETWORK_STATUS.CONTAINMENT_PENDING, + 'agent2' + ); + constructorOptions.esClient.search.mockResolvedValueOnce(searchResponse); + + const agentStatusResponse = { + agent2: { id: 'agent2', state: CROWDSTRIKE_STATUS_RESPONSE.OFFLINE }, + }; + + // @ts-expect-error private method + (client.getAgentStatusFromConnectorAction as Jest.Mock).mockResolvedValue( + agentStatusResponse + ); + + const result = await client.getAgentStatuses(agentIds); + + expect(constructorOptions.esClient.search).toHaveBeenCalled(); + expect(result).toEqual({ + agent2: { + agentId: 'agent2', + agentType: 'crowdstrike', + found: true, + isolated: false, + lastSeen: '2023-01-01', + status: HostStatus.OFFLINE, + pendingActions: {}, + }, + }); + }); + it('should set isolated to true if host is pending release', async () => { + const agentIds = ['agent2']; + const searchResponse: estypes.SearchResponse = getMockSearchResponse( + CROWDSTRIKE_NETWORK_STATUS.LIFT_CONTAINMENT_PENDING, + 'agent2' + ); + constructorOptions.esClient.search.mockResolvedValueOnce(searchResponse); + + const agentStatusResponse = { + agent2: { id: 'agent2', state: CROWDSTRIKE_STATUS_RESPONSE.OFFLINE }, + }; + + // @ts-expect-error private method + (client.getAgentStatusFromConnectorAction as Jest.Mock).mockResolvedValue( + agentStatusResponse + ); + + const result = await client.getAgentStatuses(agentIds); + + expect(constructorOptions.esClient.search).toHaveBeenCalled(); + expect(result).toEqual({ + agent2: { + agentId: 'agent2', + agentType: 'crowdstrike', + found: true, + isolated: true, + lastSeen: '2023-01-01', + pendingActions: {}, + status: HostStatus.OFFLINE, + }, + }); + }); + it('should handle error and log it', async () => { + const agentIds = ['agent1', 'agent2']; + const error = new Error('ES search failed'); + constructorOptions.esClient.search.mockRejectedValue(error); + + await expect(client.getAgentStatuses(agentIds)).rejects.toThrow(AgentStatusClientError); + + // @ts-expect-error private method + expect(client.log.error).toHaveBeenCalledWith(expect.any(AgentStatusClientError)); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/server/endpoint/services/agent/clients/crowdstrike/crowdstrike_agent_status_client.ts b/x-pack/plugins/security_solution/server/endpoint/services/agent/clients/crowdstrike/crowdstrike_agent_status_client.ts new file mode 100644 index 0000000000000..61d0ae9a7ef5e --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/services/agent/clients/crowdstrike/crowdstrike_agent_status_client.ts @@ -0,0 +1,177 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + CROWDSTRIKE_CONNECTOR_ID, + SUB_ACTION, +} from '@kbn/stack-connectors-plugin/common/crowdstrike/constants'; +import type { ActionTypeExecutorResult } from '@kbn/actions-plugin/common'; +import type { CrowdstrikeGetAgentOnlineStatusResponse } from '@kbn/stack-connectors-plugin/common/crowdstrike/types'; +import { keyBy } from 'lodash'; +import type { ActionsClient } from '@kbn/actions-plugin/server'; +import { DEFAULT_MAX_TABLE_QUERY_SIZE } from '../../../../../../common/constants'; +import type { RawCrowdstrikeInfo } from './types'; +import { catchAndWrapError } from '../../../../utils'; +import { getPendingActionsSummary, NormalizedExternalConnectorClient } from '../../..'; +import { type AgentStatusRecords, HostStatus } from '../../../../../../common/endpoint/types'; +import type { ResponseActionAgentType } from '../../../../../../common/endpoint/service/response_actions/constants'; +import { AgentStatusClient } from '../lib/base_agent_status_client'; +import { AgentStatusClientError } from '../errors'; + +const CROWDSTRIKE_AGENT_INDEX_PATTERN = `logs-crowdstrike.host-*`; + +export enum CROWDSTRIKE_NETWORK_STATUS { + NORMAL = 'normal', + CONTAINED = 'contained', + LIFT_CONTAINMENT_PENDING = 'lift_containment_pending', + CONTAINMENT_PENDING = 'containment_pending', +} + +export enum CROWDSTRIKE_STATUS_RESPONSE { + ONLINE = 'online', + OFFLINE = 'offline', + UNKNOWN = 'unknown', +} + +export class CrowdstrikeAgentStatusClient extends AgentStatusClient { + protected readonly agentType: ResponseActionAgentType = 'crowdstrike'; + + private async getAgentStatusFromConnectorAction(agentIds: string[]) { + const connectorActions = new NormalizedExternalConnectorClient( + this.options.connectorActionsClient as ActionsClient, + this.log + ); + connectorActions.setup(CROWDSTRIKE_CONNECTOR_ID); + + const agentStatusResponse = (await connectorActions.execute({ + params: { + subAction: SUB_ACTION.GET_AGENT_ONLINE_STATUS, + subActionParams: { + ids: agentIds, + }, + }, + })) as ActionTypeExecutorResult; + + return keyBy(agentStatusResponse.data?.resources, 'id'); + } + + async getAgentStatuses(agentIds: string[]): Promise { + const esClient = this.options.esClient; + const metadataService = this.options.endpointService.getEndpointMetadataService(); + const sortField = 'crowdstrike.host.last_seen'; + + const query = { + bool: { + must: [ + { + bool: { + filter: [ + { + terms: { + 'crowdstrike.host.id': agentIds, + }, + }, + ], + }, + }, + ], + }, + }; + + try { + const [searchResponse, allPendingActions] = await Promise.all([ + esClient.search( + { + index: CROWDSTRIKE_AGENT_INDEX_PATTERN, + from: 0, + size: DEFAULT_MAX_TABLE_QUERY_SIZE, + query, + collapse: { + // TODO: check if we should use crowdstrike.cid instead + field: 'crowdstrike.host.id', + inner_hits: { + name: 'most_recent', + size: 1, + sort: [ + { + [sortField]: { + order: 'desc', + }, + }, + ], + }, + }, + sort: [ + { + [sortField]: { + order: 'desc', + }, + }, + ], + _source: false, + }, + { ignore: [404] } + ), + + getPendingActionsSummary(esClient, metadataService, this.log, agentIds), + ]).catch(catchAndWrapError); + + const mostRecentAgentInfosByAgentId = searchResponse?.hits?.hits?.reduce< + Record + >((acc, hit) => { + // TODO TC: check if we should use crowdstrike.cid instead + if (hit.fields?.['crowdstrike.host.id'][0]) { + acc[hit.fields?.['crowdstrike.host.id'][0]] = + hit.inner_hits?.most_recent.hits.hits[0]._source; + } + + return acc; + }, {}); + + const agentStatuses = await this.getAgentStatusFromConnectorAction(agentIds); + + return agentIds.reduce((acc, agentId) => { + const agentInfo = mostRecentAgentInfosByAgentId[agentId].crowdstrike; + + const agentStatus = agentStatuses[agentId]; + const pendingActions = allPendingActions.find( + (agentPendingActions) => agentPendingActions.agent_id === agentId + ); + + acc[agentId] = { + agentId, + agentType: this.agentType, + // TODO: check if we should use crowdstrike.cid instead + found: agentInfo?.host.id === agentId, + isolated: + agentInfo?.host.status === CROWDSTRIKE_NETWORK_STATUS.CONTAINED || + agentInfo?.host.status === CROWDSTRIKE_NETWORK_STATUS.LIFT_CONTAINMENT_PENDING, + lastSeen: agentInfo?.host.last_seen || '', + status: + agentStatus?.state === CROWDSTRIKE_STATUS_RESPONSE.ONLINE + ? HostStatus.HEALTHY + : // TODO TC: not sure what the UNKNOWN is - still to be figured + agentStatus?.state === CROWDSTRIKE_STATUS_RESPONSE.UNKNOWN + ? HostStatus.OFFLINE + : HostStatus.OFFLINE, + + pendingActions: pendingActions?.pending_actions ?? {}, + }; + + return acc; + }, {}); + } catch (err) { + const error = new AgentStatusClientError( + `Failed to fetch crowdstrike agent status for agentIds: [${agentIds}], failed with: ${err.message}`, + 500, + err + ); + this.log.error(error); + throw error; + } + } +} diff --git a/x-pack/plugins/security_solution/server/endpoint/services/agent/clients/crowdstrike/types.ts b/x-pack/plugins/security_solution/server/endpoint/services/agent/clients/crowdstrike/types.ts new file mode 100644 index 0000000000000..87998a86b0c7c --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/services/agent/clients/crowdstrike/types.ts @@ -0,0 +1,268 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { CROWDSTRIKE_NETWORK_STATUS } from './crowdstrike_agent_status_client'; + +interface Agent { + name: string; + id: string; + ephemeral_id: string; + type: string; + version: string; +} + +interface ElasticAgent { + id: string; + version: string; + snapshot: boolean; +} + +interface Error { + message: string[]; +} + +interface Input { + type: string; +} + +interface Ecs { + version: string; +} + +interface Related { + hosts: string[]; + ip: string[]; + hash: string[]; +} + +interface DataStream { + namespace: string; + type: string; + dataset: string; +} + +interface Geo { + continent_name: string; + region_iso_code: string; + city_name: string; + country_iso_code: string; + country_name: string; + location: { + lon: number; + lat: number; + }; + region_name: string; +} + +interface Os { + platform: string; + full: string; +} + +interface Host { + geo: Geo; + hostname: string; + os: Os; + ip: string[]; + mac: string[]; +} + +interface Policy { + policy_type: string; + assigned_date: string; + policy_id: string; + applied: boolean; + applied_date: string; +} + +interface GlobalConfigPolicy extends Policy { + settings_hash: string; +} + +type DeviceControlPolicy = Policy; + +interface FirewallPolicy extends Policy { + rule_set_id: string; +} + +interface RemoteResponsePolicy extends Policy { + settings_hash: string; +} + +interface SensorUpdatePolicy extends Policy { + uninstall_protection: string; + settings_hash: string; +} + +interface PreventionPolicy extends Policy { + rule_groups: unknown[]; + settings_hash: string; +} + +interface DevicePolicies { + global_config: GlobalConfigPolicy; + device_control: DeviceControlPolicy; + firewall: FirewallPolicy; + remote_response: RemoteResponsePolicy; + sensor_update: SensorUpdatePolicy; + prevention: PreventionPolicy; +} + +interface Json { + connection_ip: string; + chassis_type: string; + reduced_functionality_mode: string; + first_seen: string; + system_manufacturer: string; + config_id_base: string; + last_seen: string; + chassis_type_desc: string; + policies: Array<{ + applied: boolean; + applied_date: string; + assigned_date: string; + policy_id: string; + policy_type: string; + rule_groups: unknown[]; + settings_hash: string; + }>; + cpu_signature: string; + machine_domain: string; + minor_version: string; + system_product_name: string; + hostname: string; + os_build: string; + mac_address: string; + product_type_desc: string; + platform_name: string; + external_ip: string; + agent_load_flags: string; + device_id: string; + group_hash: string; + provision_status: string; + os_version: string; + groups: string[]; + serial_number: string; + bios_version: string; + modified_timestamp: string; + tags: string[]; + local_ip: string; + site_name: string; + agent_version: string; + major_version: string; + kernel_version: string; + meta: { + version: string; + version_string: string; + }; + agent_local_time: string; + bios_manufacturer: string; + platform_id: string; + device_policies: DevicePolicies; + config_id_build: string; + config_id_platform: string; + cid: string; + status: string; +} + +interface Event { + agent_id_status: string; + ingested: string; + original: string; + kind: string; + category: string[]; + type: string[]; + dataset: string; +} + +interface CrowdstrikeHost { + connection_ip: string; + agent: { + local_time: string; + load_flags: string; + version: string; + }; + chassis_type: { + value: string; + desc: string; + }; + reduced_functionality_mode: string; + first_seen: string; + last_seen: string; + bios: { + version: string; + manufacturer: string; + }; + policies: Policy[]; + cpu_signature: string; + machine_domain: string; + platform: { + name: string; + id: string; + }; + minor_version: string; + hostname: string; + mac_address: string; + product_type_desc: string; + id: string; + external_ip: string; + os: { + build: string; + version: string; + }; + group_hash: string; + provision_status: string; + groups: string[]; + serial_number: string; + modified_timestamp: string; + tags: string[]; + local_ip: string; + site_name: string; + major_version: string; + system: { + product_name: string; + manufacturer: string; + }; + kernel_version: string; + config_id: { + build: string; + platform: string; + base: string; + }; + meta: { + version: string; + version_string: string; + }; + device_policies: DevicePolicies; + cid: string; + status: CROWDSTRIKE_NETWORK_STATUS; +} + +interface Crowdstrike { + host: CrowdstrikeHost; +} + +interface Device { + id: string; +} + +export interface RawCrowdstrikeInfo { + agent: Agent; + elastic_agent: ElasticAgent; + error: Error; + tags: string[]; + input: Input; + '@timestamp': string; + ecs: Ecs; + related: Related; + data_stream: DataStream; + host: Host; + json: Json; + event: Event; + crowdstrike: Crowdstrike; + device: Device; +} diff --git a/x-pack/plugins/security_solution/server/endpoint/services/agent/clients/get_agent_status_client.test.ts b/x-pack/plugins/security_solution/server/endpoint/services/agent/clients/get_agent_status_client.test.ts new file mode 100644 index 0000000000000..0290bd3e9d562 --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/services/agent/clients/get_agent_status_client.test.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getAgentStatusClient } from './get_agent_status_client'; +import { EndpointAgentStatusClient } from './endpoint/endpoint_agent_status_client'; +import { SentinelOneAgentStatusClient } from './sentinel_one/sentinel_one_agent_status_client'; +import { CrowdstrikeAgentStatusClient } from './crowdstrike/crowdstrike_agent_status_client'; +import { UnsupportedAgentTypeError } from './errors'; +import { savedObjectsClientMock } from '@kbn/core-saved-objects-api-server-mocks'; +import { CrowdstrikeMock } from '../../actions/clients/crowdstrike/mocks'; +import { responseActionsClientMock } from '../../actions/clients/mocks'; + +describe('getAgentStatusClient', () => { + const mockedConstructorOptions = responseActionsClientMock.createConstructorOptions(); + const constructorOptions = { + esClient: mockedConstructorOptions.esClient, + soClient: savedObjectsClientMock.create(), + connectorActionsClient: CrowdstrikeMock.createConnectorActionsClient(), + endpointService: mockedConstructorOptions.endpointService, + }; + + it('returns an EndpointAgentStatusClient for endpoint agent type', () => { + const client = getAgentStatusClient('endpoint', constructorOptions); + expect(client).toBeInstanceOf(EndpointAgentStatusClient); + }); + + it('returns a SentinelOneAgentStatusClient for sentinel_one agent type', () => { + const client = getAgentStatusClient('sentinel_one', constructorOptions); + expect(client).toBeInstanceOf(SentinelOneAgentStatusClient); + }); + + it('returns a CrowdstrikeAgentStatusClient for crowdstrike agent type', () => { + const client = getAgentStatusClient('crowdstrike', constructorOptions); + expect(client).toBeInstanceOf(CrowdstrikeAgentStatusClient); + }); + + it('throws an UnsupportedAgentTypeError for unsupported agent type', () => { + // @ts-expect-error testing unsupported agent type + expect(() => getAgentStatusClient('unsupported_agent_type', constructorOptions)).toThrow( + UnsupportedAgentTypeError + ); + }); +}); diff --git a/x-pack/plugins/security_solution/server/endpoint/services/agent/clients/get_agent_status_client.ts b/x-pack/plugins/security_solution/server/endpoint/services/agent/clients/get_agent_status_client.ts index 9c337d997c49c..6adbbb05d3408 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/agent/clients/get_agent_status_client.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/agent/clients/get_agent_status_client.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { CrowdstrikeAgentStatusClient } from './crowdstrike/crowdstrike_agent_status_client'; import { SentinelOneAgentStatusClient } from './sentinel_one/sentinel_one_agent_status_client'; import type { AgentStatusClientInterface } from './lib/types'; import type { AgentStatusClientOptions } from './lib/base_agent_status_client'; @@ -27,8 +28,8 @@ export const getAgentStatusClient = ( return new EndpointAgentStatusClient(constructorOptions); case 'sentinel_one': return new SentinelOneAgentStatusClient(constructorOptions); - // case 'crowdstrike': - // // TODO TC: Currently we do not support CrowdStrike agent status - will be done in a follow up PR + case 'crowdstrike': + return new CrowdstrikeAgentStatusClient(constructorOptions); default: throw new UnsupportedAgentTypeError( `Agent type [${agentType}] does not support agent status` diff --git a/x-pack/plugins/security_solution/server/endpoint/services/agent/clients/lib/base_agent_status_client.ts b/x-pack/plugins/security_solution/server/endpoint/services/agent/clients/lib/base_agent_status_client.ts index 7722427fc18c8..19b90ff5d09ab 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/agent/clients/lib/base_agent_status_client.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/agent/clients/lib/base_agent_status_client.ts @@ -7,6 +7,7 @@ import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import type { Logger } from '@kbn/logging'; import type { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; +import type { ActionsClient } from '@kbn/actions-plugin/server'; import type { AgentStatusRecords } from '../../../../../../common/endpoint/types/agents'; import type { ResponseActionAgentType } from '../../../../../../common/endpoint/service/response_actions/constants'; import type { EndpointAppContextService } from '../../../../endpoint_app_context_services'; @@ -17,6 +18,7 @@ export interface AgentStatusClientOptions { endpointService: EndpointAppContextService; esClient: ElasticsearchClient; soClient: SavedObjectsClientContract; + connectorActionsClient?: ActionsClient; } export abstract class AgentStatusClient implements AgentStatusClientInterface { diff --git a/x-pack/plugins/security_solution/server/endpoint/services/agent/clients/sentinel_one/sentinel_one_agent_status_client.ts b/x-pack/plugins/security_solution/server/endpoint/services/agent/clients/sentinel_one/sentinel_one_agent_status_client.ts index 2335cff5db8d3..3509cee521fc0 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/agent/clients/sentinel_one/sentinel_one_agent_status_client.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/agent/clients/sentinel_one/sentinel_one_agent_status_client.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { DEFAULT_MAX_TABLE_QUERY_SIZE } from '../../../../../../common/constants'; import { catchAndWrapError } from '../../../../utils'; import { getPendingActionsSummary } from '../../..'; import type { RawSentinelOneInfo } from './types'; @@ -54,7 +55,7 @@ export class SentinelOneAgentStatusClient extends AgentStatusClient { { index: SENTINEL_ONE_AGENT_INDEX_PATTERN, from: 0, - size: 10000, + size: DEFAULT_MAX_TABLE_QUERY_SIZE, query, collapse: { field: 'sentinel_one.agent.uuid', diff --git a/x-pack/plugins/security_solution/server/endpoint/services/feature_usage/feature_keys.ts b/x-pack/plugins/security_solution/server/endpoint/services/feature_usage/feature_keys.ts index b7e8b8ab87548..c367c3d1bd91a 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/feature_usage/feature_keys.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/feature_usage/feature_keys.ts @@ -23,6 +23,8 @@ export const FEATURE_KEYS = { GET_FILE: 'Get file', UPLOAD: 'Upload file', EXECUTE: 'Execute command', + // TODO: for API changes in a subsequent PR + // SCAN: 'Scan files', ALERTS_BY_PROCESS_ANCESTRY: 'Get related alerts by process ancestry', ENDPOINT_EXCEPTIONS: 'Endpoint exceptions', } as const; @@ -39,6 +41,8 @@ const RESPONSE_ACTIONS_FEATURE_KEY: Readonly; @@ -104,8 +103,20 @@ export const InvestigationFieldsCombined = z.union([ LegacyInvestigationFields, ]); +/** + * This is the same type as RuleSource, but with the keys in camelCase. Intended + * for internal use only (not for API responses). + */ export type RuleSourceCamelCased = z.infer; -export const RuleSourceCamelCased = RuleSource.transform(convertObjectKeysToCamelCase); +export const RuleSourceCamelCased = z.discriminatedUnion('type', [ + z.object({ + type: z.literal('external'), + isCustomized: IsExternalRuleCustomized, + }), + z.object({ + type: z.literal('internal'), + }), +]); // Conversion to an interface has to be disabled for the entire file; otherwise, // the resulting union would not be assignable to Alerting's RuleParams due to a diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_risk_scores.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_risk_scores.ts index 3c930ec07e666..9f99a9ae4a561 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_risk_scores.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/calculate_risk_scores.ts @@ -13,10 +13,7 @@ import type { import type { ElasticsearchClient, Logger } from '@kbn/core/server'; import { ALERT_RISK_SCORE, - ALERT_RULE_NAME, - ALERT_UUID, ALERT_WORKFLOW_STATUS, - EVENT_KIND, } from '@kbn/rule-registry-plugin/common/technical_rule_data_field_names'; import type { RiskScoresPreviewResponse } from '../../../../common/api/entity_analytics/risk_engine/preview_route.gen'; import type { @@ -28,6 +25,7 @@ import { type IdentifierType, getRiskLevel, RiskCategories, + RiskWeightTypes, } from '../../../../common/entity_analytics/risk_engine'; import { withSecuritySpan } from '../../../utils/with_security_span'; import type { AssetCriticalityRecord } from '../../../../common/api/entity_analytics'; @@ -38,24 +36,13 @@ import { normalize, } from '../asset_criticality/helpers'; import { getAfterKeyForIdentifierType, getFieldForIdentifier } from './helpers'; -import { - buildCategoryCountDeclarations, - buildCategoryAssignment, - buildCategoryScoreDeclarations, - buildWeightingOfScoreByCategory, - getGlobalWeightForIdentifierType, -} from './risk_weights'; import type { CalculateRiskScoreAggregations, CalculateScoresParams, RiskScoreBucket, } from '../types'; -import { - MAX_INPUTS_COUNT, - RISK_SCORING_INPUTS_COUNT_MAX, - RISK_SCORING_SUM_MAX, - RISK_SCORING_SUM_VALUE, -} from './constants'; +import { RISK_SCORING_SUM_MAX, RISK_SCORING_SUM_VALUE } from './constants'; +import { getPainlessScripts, type PainlessScripts } from './painless'; const formatForResponse = ({ bucket, @@ -118,67 +105,22 @@ const filterFromRange = (range: CalculateScoresParams['range']): QueryDslQueryCo range: { '@timestamp': { lt: range.end, gte: range.start } }, }); -const buildReduceScript = ({ - globalIdentifierTypeWeight, -}: { - globalIdentifierTypeWeight?: number; -}): string => { - return ` - Map results = new HashMap(); - List inputs = []; - for (state in states) { - inputs.addAll(state.inputs) - } - Collections.sort(inputs, (a, b) -> b.get('weighted_score').compareTo(a.get('weighted_score'))); - - double num_inputs_to_score = Math.min(inputs.length, params.max_risk_inputs_per_identity); - results['notes'] = []; - if (num_inputs_to_score == params.max_risk_inputs_per_identity) { - results['notes'].add('Number of risk inputs (' + inputs.length + ') exceeded the maximum allowed (' + params.max_risk_inputs_per_identity + ').'); - } - - ${buildCategoryScoreDeclarations()} - ${buildCategoryCountDeclarations()} - - double total_score = 0; - double current_score = 0; - List risk_inputs = []; - for (int i = 0; i < num_inputs_to_score; i++) { - current_score = inputs[i].weighted_score / Math.pow(i + 1, params.p); - - if (i < ${MAX_INPUTS_COUNT}) { - inputs[i]["contribution"] = 100 * current_score / params.risk_cap; - risk_inputs.add(inputs[i]); - } - - ${buildCategoryAssignment()} - total_score += current_score; - } - - ${globalIdentifierTypeWeight != null ? `total_score *= ${globalIdentifierTypeWeight};` : ''} - double score_norm = 100 * total_score / params.risk_cap; - results['score'] = total_score; - results['normalized_score'] = score_norm; - results['risk_inputs'] = risk_inputs; - - return results; - `; -}; - const buildIdentifierTypeAggregation = ({ afterKeys, identifierType, pageSize, weights, alertSampleSizePerShard, + scriptedMetricPainless, }: { afterKeys: AfterKeys; identifierType: IdentifierType; pageSize: number; weights?: RiskScoreWeights; alertSampleSizePerShard: number; + scriptedMetricPainless: PainlessScripts; }): AggregationsAggregationContainer => { - const globalIdentifierTypeWeight = getGlobalWeightForIdentifierType({ identifierType, weights }); + const globalIdentifierTypeWeight = getGlobalWeightForIdentifierType(identifierType, weights); const identifierField = getFieldForIdentifier(identifierType); return { @@ -204,33 +146,15 @@ const buildIdentifierTypeAggregation = ({ aggs: { risk_details: { scripted_metric: { - init_script: 'state.inputs = []', - map_script: ` - Map fields = new HashMap(); - String category = doc['${EVENT_KIND}'].value; - double score = doc['${ALERT_RISK_SCORE}'].value; - double weighted_score = 0.0; - - fields.put('time', doc['@timestamp'].value); - fields.put('rule_name', doc['${ALERT_RULE_NAME}'].value); - - fields.put('category', category); - fields.put('index', doc['_index'].value); - fields.put('id', doc['${ALERT_UUID}'].value); - fields.put('score', score); - - ${buildWeightingOfScoreByCategory({ userWeights: weights, identifierType })} - fields.put('weighted_score', weighted_score); - - state.inputs.add(fields); - `, - combine_script: 'return state;', + init_script: scriptedMetricPainless.init, + map_script: scriptedMetricPainless.map, + combine_script: scriptedMetricPainless.combine, params: { - max_risk_inputs_per_identity: RISK_SCORING_INPUTS_COUNT_MAX, p: RISK_SCORING_SUM_VALUE, risk_cap: RISK_SCORING_SUM_MAX, + global_identifier_type_weight: globalIdentifierTypeWeight || 1, }, - reduce_script: buildReduceScript({ globalIdentifierTypeWeight }), + reduce_script: scriptedMetricPainless.reduce, }, }, }, @@ -286,6 +210,12 @@ const processScores = async ({ }); }; +export const getGlobalWeightForIdentifierType = ( + identifierType: IdentifierType, + weights?: RiskScoreWeights +): number | undefined => + weights?.find((weight) => weight.type === RiskWeightTypes.global)?.[identifierType]; + export const calculateRiskScores = async ({ afterKeys: userAfterKeys, assetCriticalityService, @@ -307,6 +237,7 @@ export const calculateRiskScores = async ({ } & CalculateScoresParams): Promise => withSecuritySpan('calculateRiskScores', async () => { const now = new Date().toISOString(); + const scriptedMetricPainless = await getPainlessScripts(); const filter = [ filterFromRange(range), { bool: { must_not: { term: { [ALERT_WORKFLOW_STATUS]: 'closed' } } } }, @@ -345,6 +276,7 @@ export const calculateRiskScores = async ({ pageSize, weights, alertSampleSizePerShard, + scriptedMetricPainless, }); return aggs; }, {} as Record), diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/constants.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/constants.ts index 73f93d71b11f9..6a691eac42734 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/constants.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/constants.ts @@ -16,11 +16,6 @@ export const RISK_SCORING_SUM_VALUE = 1.5; */ export const RISK_SCORING_SUM_MAX = 261.2; -/** - * The risk scoring algorithm can only process a finite number of risk inputs per identity; this value represents the maximum number of inputs that will be processed. - */ -export const RISK_SCORING_INPUTS_COUNT_MAX = 999999; - /** * This value represents the maximum possible risk score after normalization. */ diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/painless/index.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/painless/index.test.ts new file mode 100644 index 0000000000000..e21a6afeff326 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/painless/index.test.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getPainlessScripts } from '.'; + +describe('getPainlessScripts', () => { + // to update snapshot run `yarn test:jest x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/painless/index.test.ts -u` + test('Scripts should not have changed. If this change is intentional, ensure that Serverless scripted metric allowlists are updated', async () => { + const scripts = await getPainlessScripts(); + + expect(scripts).toMatchInlineSnapshot(` + Object { + "combine": "return state;", + "init": "state.inputs = []", + "map": "Map fields = new HashMap();fields.put('id', doc['kibana.alert.uuid'].value);fields.put('index', doc['_index'].value);fields.put('time', doc['@timestamp'].value);fields.put('rule_name', doc['kibana.alert.rule.name'].value);fields.put('category', doc['event.kind'].value);fields.put('score', doc['kibana.alert.risk_score'].value);state.inputs.add(fields); ", + "reduce": "Map results = new HashMap();results['notes'] = [];results['category_1_score'] = 0.0;results['category_1_count'] = 0;results['risk_inputs'] = [];results['score'] = 0.0;def inputs = states[0].inputs;Collections.sort(inputs, (a, b) -> b.get('score').compareTo(a.get('score')));for (int i = 0; i < inputs.length; i++) { double current_score = inputs[i].score / Math.pow(i + 1, params.p); if (i < 10) { inputs[i][\\"contribution\\"] = 100 * current_score / params.risk_cap; results['risk_inputs'].add(inputs[i]); } results['category_1_score'] += current_score; results['category_1_count'] += 1; results['score'] += current_score;}results['score'] *= params.global_identifier_type_weight;results['normalized_score'] = 100 * results['score'] / params.risk_cap;return results;", + } + `); + }); +}); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/painless/index.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/painless/index.ts new file mode 100644 index 0000000000000..896340262b21c --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/painless/index.ts @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import fs from 'fs'; +import { flow } from 'lodash'; + +const PHASES = ['init', 'map', 'combine', 'reduce'] as const; + +type Phase = typeof PHASES[number]; +export type PainlessScripts = Record; + +const removeNewlines = (content: string) => content.replace(/\n/g, ''); +const condenseMultipleSpaces = (content: string) => content.replace(/\s+/g, ' '); +const removeComments = (content: string) => content.replace(/\/\/.*/g, ''); +const minifyContent = flow(removeComments, removeNewlines, condenseMultipleSpaces); + +const readScript = async (phase: Phase) => { + const content = await fs.promises.readFile(`${__dirname}/risk_scoring_${phase}.painless`, 'utf8'); + return minifyContent(content); +}; + +let cache: PainlessScripts | undefined; + +export const getPainlessScripts = async (): Promise => { + if (cache) { + return cache; + } + + const [init, map, combine, reduce] = await Promise.all(PHASES.map(readScript)); + + // The cache will only ever have one value, so we can safely update it + // un-atomicly without worrying about lost updates. + // eslint-disable-next-line require-atomic-updates + cache = { init, map, combine, reduce }; + return cache; +}; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/painless/risk_scoring_combine.painless b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/painless/risk_scoring_combine.painless new file mode 100644 index 0000000000000..da2a75d569f18 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/painless/risk_scoring_combine.painless @@ -0,0 +1 @@ +return state; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/painless/risk_scoring_init.painless b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/painless/risk_scoring_init.painless new file mode 100644 index 0000000000000..5ee9376d701ad --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/painless/risk_scoring_init.painless @@ -0,0 +1 @@ +state.inputs = [] diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/painless/risk_scoring_map.painless b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/painless/risk_scoring_map.painless new file mode 100644 index 0000000000000..3d79df51be0e8 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/painless/risk_scoring_map.painless @@ -0,0 +1,8 @@ +Map fields = new HashMap(); +fields.put('id', doc['kibana.alert.uuid'].value); +fields.put('index', doc['_index'].value); +fields.put('time', doc['@timestamp'].value); +fields.put('rule_name', doc['kibana.alert.rule.name'].value); +fields.put('category', doc['event.kind'].value); +fields.put('score', doc['kibana.alert.risk_score'].value); +state.inputs.add(fields); \ No newline at end of file diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/painless/risk_scoring_reduce.painless b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/painless/risk_scoring_reduce.painless new file mode 100644 index 0000000000000..629a925522590 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/painless/risk_scoring_reduce.painless @@ -0,0 +1,41 @@ +Map results = new HashMap(); +results['notes'] = []; +results['category_1_score'] = 0.0; +results['category_1_count'] = 0; +results['risk_inputs'] = []; +results['score'] = 0.0; + +def inputs = states[0].inputs; + +// Currently the alerts index only has one shard so there will only be one state +// If there are multiple shards we will need these lines +// List inputs = []; +// for (state in states) { +// inputs.addAll(state.inputs) +// } + +// sorting is needed even though we sort in the parent query because the scripted metric +// agg does not guarantee order. +Collections.sort(inputs, (a, b) -> b.get('score').compareTo(a.get('score'))); + +for (int i = 0; i < inputs.length; i++) { + double current_score = inputs[i].score / Math.pow(i + 1, params.p); + + if (i < 10) { + inputs[i]["contribution"] = 100 * current_score / params.risk_cap; + results['risk_inputs'].add(inputs[i]); + } + +// every input is of type signal at the moment +// if (inputs[i].category == 'signal') { + results['category_1_score'] += current_score; + results['category_1_count'] += 1; +// } + + results['score'] += current_score; +} + +results['score'] *= params.global_identifier_type_weight; +results['normalized_score'] = 100 * results['score'] / params.risk_cap; + +return results; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_weights.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_weights.test.ts deleted file mode 100644 index 86bdc0d0e6be0..0000000000000 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_weights.test.ts +++ /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 { RiskWeightTypes, RiskCategories } from '../../../../common/entity_analytics/risk_engine'; -import { - buildCategoryAssignment, - buildCategoryWeights, - buildWeightingOfScoreByCategory, -} from './risk_weights'; - -describe('buildCategoryWeights', () => { - it('returns the default weights if nothing else is provided', () => { - const result = buildCategoryWeights(); - - expect(result).toEqual([ - { host: 1, type: RiskWeightTypes.riskCategory, user: 1, value: RiskCategories.category_1 }, - ]); - }); - - it('allows user weights to override defaults', () => { - const result = buildCategoryWeights([ - { - type: RiskWeightTypes.riskCategory, - value: RiskCategories.category_1, - host: 0.1, - user: 0.2, - }, - ]); - - expect(result).toEqual([ - { - host: 0.1, - type: RiskWeightTypes.riskCategory, - user: 0.2, - value: RiskCategories.category_1, - }, - ]); - }); - - it('uses default category weights if unspecified in user-provided weight', () => { - const result = buildCategoryWeights([ - { type: RiskWeightTypes.riskCategory, value: RiskCategories.category_1, host: 0.1 }, - ]); - - expect(result).toEqual([ - { host: 0.1, type: RiskWeightTypes.riskCategory, user: 1, value: RiskCategories.category_1 }, - ]); - }); -}); - -describe('buildCategoryAssignment', () => { - it('builds the expected assignment statement', () => { - const result = buildCategoryAssignment(); - - expect(result).toMatchInlineSnapshot( - `"if (inputs[i].category == 'signal') { results['category_1_score'] += current_score; results['category_1_count'] += 1; }"` - ); - }); -}); - -describe('buildWeightingOfScoreByCategory', () => { - it('returns default weights if no user values provided', () => { - const result = buildWeightingOfScoreByCategory({ identifierType: 'user' }); - - expect(result).toMatchInlineSnapshot( - `"if (category == 'signal') { weighted_score = score * 1; } else { weighted_score = score; }"` - ); - }); - - it('returns default weights if no weights provided', () => { - const result = buildWeightingOfScoreByCategory({ userWeights: [], identifierType: 'host' }); - - expect(result).toMatchInlineSnapshot( - `"if (category == 'signal') { weighted_score = score * 1; } else { weighted_score = score; }"` - ); - }); - - it('returns default weights if only global weights provided', () => { - const result = buildWeightingOfScoreByCategory({ - userWeights: [{ type: RiskWeightTypes.global, host: 0.1 }], - identifierType: 'host', - }); - - expect(result).toMatchInlineSnapshot( - `"if (category == 'signal') { weighted_score = score * 1; } else { weighted_score = score; }"` - ); - }); - - it('returns specified weight when a category weight is provided', () => { - const result = buildWeightingOfScoreByCategory({ - userWeights: [ - { - type: RiskWeightTypes.riskCategory, - value: RiskCategories.category_1, - host: 0.1, - user: 0.2, - }, - ], - identifierType: 'host', - }); - - expect(result).toMatchInlineSnapshot( - `"if (category == 'signal') { weighted_score = score * 0.1; } else { weighted_score = score; }"` - ); - }); - - it('returns a default weight when a category weight is provided but not the one being used', () => { - const result = buildWeightingOfScoreByCategory({ - userWeights: [ - { type: RiskWeightTypes.riskCategory, value: RiskCategories.category_1, host: 0.1 }, - ], - identifierType: 'user', - }); - - expect(result).toMatchInlineSnapshot( - `"if (category == 'signal') { weighted_score = score * 1; } else { weighted_score = score; }"` - ); - }); -}); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_weights.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_weights.ts deleted file mode 100644 index d0c7486324e30..0000000000000 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/risk_weights.ts +++ /dev/null @@ -1,103 +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 { keyBy, merge } from 'lodash'; -import type { - RiskScoreWeight, - RiskScoreWeightCategory, - RiskScoreWeightGlobal, - RiskScoreWeights, -} from '../../../../common/api/entity_analytics/common'; -import type { IdentifierType } from '../../../../common/entity_analytics/risk_engine'; -import { RiskCategories, RiskWeightTypes } from '../../../../common/entity_analytics/risk_engine'; - -const RISK_CATEGORIES = Object.values(RiskCategories); - -const DEFAULT_CATEGORY_WEIGHTS: RiskScoreWeights = RISK_CATEGORIES.map((category) => ({ - type: RiskWeightTypes.riskCategory, - value: category, - host: 1, - user: 1, -})); - -/* - * This function and its use can be deleted once we've replaced our use of event.kind with a proper risk category field. - */ -const convertCategoryToEventKindValue = (category?: string): string | undefined => - category === 'category_1' ? 'signal' : category; - -const isGlobalIdentifierTypeWeight = (weight: RiskScoreWeight): weight is RiskScoreWeightGlobal => - weight.type === RiskWeightTypes.global; -const isRiskCategoryWeight = (weight: RiskScoreWeight): weight is RiskScoreWeightCategory => - weight.type === RiskWeightTypes.riskCategory; - -export const getGlobalWeightForIdentifierType = ({ - identifierType, - weights, -}: { - identifierType: IdentifierType; - weights?: RiskScoreWeights; -}): number | undefined => { - return weights?.find(isGlobalIdentifierTypeWeight)?.[identifierType]; -}; - -const getRiskCategoryWeights = (weights?: RiskScoreWeights): RiskScoreWeightCategory[] => - weights?.filter(isRiskCategoryWeight) ?? []; - -const getWeightForIdentifierType = ( - weight: RiskScoreWeight, - identifierType: IdentifierType -): number => { - const configuredWeight = weight[identifierType]; - return typeof configuredWeight === 'number' ? configuredWeight : 1; -}; - -export const buildCategoryScoreDeclarations = (): string => { - return RISK_CATEGORIES.map((riskCategory) => `results['${riskCategory}_score'] = 0.0;`).join(''); -}; - -export const buildCategoryCountDeclarations = (): string => { - return RISK_CATEGORIES.map((riskCategory) => `results['${riskCategory}_count'] = 0;`).join(''); -}; - -export const buildCategoryWeights = (userWeights?: RiskScoreWeights): RiskScoreWeightCategory[] => { - const categoryWeights = getRiskCategoryWeights(userWeights); - - return Object.values( - merge({}, keyBy(DEFAULT_CATEGORY_WEIGHTS, 'value'), keyBy(categoryWeights, 'value')) - ); -}; - -export const buildCategoryAssignment = (): string => { - return RISK_CATEGORIES.map( - (category) => - `if (inputs[i].category == '${convertCategoryToEventKindValue( - category - )}') { results['${category}_score'] += current_score; results['${category}_count'] += 1; }` - ).join(' else '); -}; - -export const buildWeightingOfScoreByCategory = ({ - userWeights, - identifierType, -}: { - userWeights?: RiskScoreWeights; - identifierType: IdentifierType; -}): string => { - const otherClause = `weighted_score = score;`; - const categoryWeights = buildCategoryWeights(userWeights); - - return categoryWeights - .map( - (weight) => - `if (category == '${convertCategoryToEventKindValue( - weight.value - )}') { weighted_score = score * ${getWeightForIdentifierType(weight, identifierType)}; }` - ) - .join(' else ') - .concat(` else { ${otherClause} }`); -}; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/preview.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/preview.test.ts index a35f4978ebf2c..b5ff9c3487a07 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/preview.test.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/risk_score/routes/preview.test.ts @@ -8,10 +8,7 @@ import { loggerMock } from '@kbn/logging-mocks'; import { RISK_SCORE_PREVIEW_URL } from '../../../../../common/constants'; -import { - RiskCategories, - RiskWeightTypes, -} from '../../../../../common/entity_analytics/risk_engine'; +import { RiskWeightTypes } from '../../../../../common/entity_analytics/risk_engine'; import { serverMock, requestContextMock, @@ -171,8 +168,7 @@ describe('POST risk_engine/preview route', () => { const request = buildRequest({ weights: [ { - type: RiskWeightTypes.riskCategory, - value: RiskCategories.category_1, + type: RiskWeightTypes.global, host: 0.1, user: 0.2, }, @@ -186,8 +182,7 @@ describe('POST risk_engine/preview route', () => { expect.objectContaining({ weights: [ { - type: RiskWeightTypes.riskCategory, - value: RiskCategories.category_1, + type: RiskWeightTypes.global, host: 0.1, user: 0.2, }, @@ -200,8 +195,7 @@ describe('POST risk_engine/preview route', () => { const request = buildRequest({ weights: [ { - type: RiskWeightTypes.riskCategory, - value: RiskCategories.category_1, + type: RiskWeightTypes.global, host: 1.1, }, ], @@ -218,7 +212,6 @@ describe('POST risk_engine/preview route', () => { weights: [ { type: 'something new', - value: RiskCategories.category_1, host: 0.1, user: 0.2, }, 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 5b59282a320ea..f4cf62a4381b6 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/receiver.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/receiver.ts @@ -417,9 +417,7 @@ export class TelemetryReceiver implements ITelemetryReceiver { latest_metrics: { top_hits: { size: 1, - _source: { - excludes: ['*'], - }, + _source: false, sort: [ { '@timestamp': { @@ -521,6 +519,7 @@ export class TelemetryReceiver implements ITelemetryReceiver { const buckets = endpointMetadataResponse?.aggregations?.endpoint_metadata?.buckets ?? []; return buckets.reduce((cache, endpointAgentId) => { + // const id = endpointAgentId.latest_metadata.hits.hits[0]._id; const doc = endpointAgentId.latest_metadata.hits.hits[0]._source; cache.set(endpointAgentId.key, doc); return cache; diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index a2440482f537e..369648f037df2 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -566,6 +566,7 @@ export class Plugin implements ISecuritySolutionPlugin { // Assistant Tool and Feature Registration plugins.elasticAssistant.registerTools(APP_UI_ID, getAssistantTools()); plugins.elasticAssistant.registerFeatures(APP_UI_ID, { + assistantKnowledgeBaseByDefault: config.experimentalFeatures.assistantKnowledgeBaseByDefault, assistantModelEvaluation: config.experimentalFeatures.assistantModelEvaluation, }); plugins.elasticAssistant.registerFeatures('management', { diff --git a/x-pack/plugins/security_solution/tsconfig.json b/x-pack/plugins/security_solution/tsconfig.json index bb26581356fa1..68351d1dd48a1 100644 --- a/x-pack/plugins/security_solution/tsconfig.json +++ b/x-pack/plugins/security_solution/tsconfig.json @@ -201,6 +201,8 @@ "@kbn/deeplinks-security", "@kbn/react-kibana-context-render", "@kbn/search-types", - "@kbn/field-utils" + "@kbn/field-utils", + "@kbn/core-saved-objects-api-server-mocks", + "@kbn/langchain" ] } diff --git a/x-pack/plugins/security_solution_ess/public/upselling/lazy_upselling.tsx b/x-pack/plugins/security_solution_ess/public/upselling/lazy_upselling.tsx new file mode 100644 index 0000000000000..70f39b2ae70e6 --- /dev/null +++ b/x-pack/plugins/security_solution_ess/public/upselling/lazy_upselling.tsx @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { lazy } from 'react'; + +import { withSuspenseUpsell } from '@kbn/security-solution-upselling/helpers'; + +export const EntityAnalyticsUpsellingSectionLazy = withSuspenseUpsell( + lazy(() => + import('./sections/entity_analytics_upselling').then( + ({ EntityAnalyticsUpsellingSectionESS }) => ({ + default: EntityAnalyticsUpsellingSectionESS, + }) + ) + ) +); + +export const EntityAnalyticsUpsellingPageLazy = lazy(() => + import('./pages/entity_analytics_upselling').then(({ EntityAnalyticsUpsellingPageESS }) => ({ + default: EntityAnalyticsUpsellingPageESS, + })) +); diff --git a/x-pack/plugins/security_solution_ess/public/upselling/pages/entity_analytics_upselling.tsx b/x-pack/plugins/security_solution_ess/public/upselling/pages/entity_analytics_upselling.tsx new file mode 100644 index 0000000000000..d8d0dec0f914c --- /dev/null +++ b/x-pack/plugins/security_solution_ess/public/upselling/pages/entity_analytics_upselling.tsx @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EntityAnalyticsUpsellingPage } from '@kbn/security-solution-upselling/pages/entity_analytics'; +import { useKibana } from '../../common/services'; +import * as i18n from '../translations'; + +export const EntityAnalyticsUpsellingPageESS = () => { + const { services } = useKibana(); + const requiredLicense = 'Platinum'; + + return ( + + ); +}; diff --git a/x-pack/plugins/security_solution_ess/public/upselling/register_upsellings.tsx b/x-pack/plugins/security_solution_ess/public/upselling/register_upsellings.tsx index cb49e2f65a775..2f86c68821ef3 100644 --- a/x-pack/plugins/security_solution_ess/public/upselling/register_upsellings.tsx +++ b/x-pack/plugins/security_solution_ess/public/upselling/register_upsellings.tsx @@ -5,7 +5,14 @@ * 2.0. */ +import type { ILicense, LicenseType } from '@kbn/licensing-plugin/public'; import { SecurityPageName } from '@kbn/security-solution-plugin/common'; +import { + ALERT_SUPPRESSION_RULE_DETAILS, + ALERT_SUPPRESSION_RULE_FORM, + UPGRADE_ALERT_ASSIGNMENTS, + UPGRADE_INVESTIGATION_GUIDE, +} from '@kbn/security-solution-upselling/messages'; import type { MessageUpsellings, PageUpsellings, @@ -14,19 +21,13 @@ import type { UpsellingSectionId, UpsellingService, } from '@kbn/security-solution-upselling/service'; -import type { ILicense, LicenseType } from '@kbn/licensing-plugin/public'; -import React, { lazy } from 'react'; -import { - UPGRADE_ALERT_ASSIGNMENTS, - UPGRADE_INVESTIGATION_GUIDE, - ALERT_SUPPRESSION_RULE_FORM, - ALERT_SUPPRESSION_RULE_DETAILS, -} from '@kbn/security-solution-upselling/messages'; +import type React from 'react'; import type { Services } from '../common/services'; import { withServicesProvider } from '../common/services'; -const EntityAnalyticsUpsellingLazy = lazy( - () => import('@kbn/security-solution-upselling/pages/entity_analytics') -); +import { + EntityAnalyticsUpsellingPageLazy, + EntityAnalyticsUpsellingSectionLazy, +} from './lazy_upselling'; interface UpsellingsConfig { minimumLicenseRequired: LicenseType; @@ -48,7 +49,7 @@ export const registerUpsellings = ( license: ILicense, services: Services ) => { - const upsellingPagesToRegister = upsellingPages(services).reduce( + const upsellingPagesToRegister = upsellingPages.reduce( (pageUpsellings, { pageName, minimumLicenseRequired, component }) => { if (!license.hasAtLeast(minimumLicenseRequired)) { pageUpsellings[pageName] = withServicesProvider(component, services); @@ -61,7 +62,7 @@ export const registerUpsellings = ( const upsellingSectionsToRegister = upsellingSections.reduce( (sectionUpsellings, { id, minimumLicenseRequired, component }) => { if (!license.hasAtLeast(minimumLicenseRequired)) { - sectionUpsellings[id] = component; + sectionUpsellings[id] = withServicesProvider(component, services); } return sectionUpsellings; }, @@ -84,25 +85,23 @@ export const registerUpsellings = ( }; // Upsellings for entire pages, linked to a SecurityPageName -export const upsellingPages: (services: Services) => UpsellingPages = (services) => [ +export const upsellingPages: UpsellingPages = [ // It is highly advisable to make use of lazy loaded components to minimize bundle size. { pageName: SecurityPageName.entityAnalytics, minimumLicenseRequired: 'platinum', - component: () => ( - - ), + component: EntityAnalyticsUpsellingPageLazy, }, ]; // Upsellings for sections, linked by arbitrary ids export const upsellingSections: UpsellingSections = [ // It is highly advisable to make use of lazy loaded components to minimize bundle size. + { + id: 'entity_analytics_panel', + minimumLicenseRequired: 'platinum', + component: EntityAnalyticsUpsellingSectionLazy, + }, ]; // Upsellings for sections, linked by arbitrary ids diff --git a/x-pack/plugins/security_solution_ess/public/upselling/sections/entity_analytics_upselling.tsx b/x-pack/plugins/security_solution_ess/public/upselling/sections/entity_analytics_upselling.tsx new file mode 100644 index 0000000000000..4506999f8bd9d --- /dev/null +++ b/x-pack/plugins/security_solution_ess/public/upselling/sections/entity_analytics_upselling.tsx @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EntityAnalyticsUpsellingSection } from '@kbn/security-solution-upselling/sections/entity_analytics'; +import { useKibana } from '../../common/services'; +import * as i18n from '../translations'; + +export const EntityAnalyticsUpsellingSectionESS = () => { + const { services } = useKibana(); + const requiredLicense = 'Platinum'; + return ( + + ); +}; diff --git a/x-pack/plugins/security_solution_ess/public/upselling/translations.ts b/x-pack/plugins/security_solution_ess/public/upselling/translations.ts new file mode 100644 index 0000000000000..9af27d3ca5242 --- /dev/null +++ b/x-pack/plugins/security_solution_ess/public/upselling/translations.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const UPGRADE_LICENSE_MESSAGE = (requiredLicense: string) => + i18n.translate('xpack.securitySolutionEss.upselling.upgradeLicenseMessage', { + defaultMessage: 'This feature is available with {requiredLicense} or higher subscription', + values: { + requiredLicense, + }, + }); diff --git a/x-pack/plugins/security_solution_serverless/public/upselling/lazy_upselling.tsx b/x-pack/plugins/security_solution_serverless/public/upselling/lazy_upselling.tsx index 71f787e19c3bd..b7e4640608928 100644 --- a/x-pack/plugins/security_solution_serverless/public/upselling/lazy_upselling.tsx +++ b/x-pack/plugins/security_solution_serverless/public/upselling/lazy_upselling.tsx @@ -5,19 +5,9 @@ * 2.0. */ -import React, { lazy, Suspense } from 'react'; -import { EuiLoadingSpinner } from '@elastic/eui'; +import { lazy } from 'react'; -const withSuspenseUpsell = ( - Component: React.ComponentType -): React.FC => - function WithSuspenseUpsell(props) { - return ( - }> - - - ); - }; +import { withSuspenseUpsell } from '@kbn/security-solution-upselling/helpers'; export const ThreatIntelligencePaywallLazy = withSuspenseUpsell( lazy(() => import('./pages/threat_intelligence_paywall')) @@ -31,6 +21,22 @@ export const EndpointExceptionsDetailsUpsellingLazy = withSuspenseUpsell( lazy(() => import('./pages/endpoint_management/endpoint_exceptions_details')) ); -export const EntityAnalyticsUpsellingLazy = withSuspenseUpsell( - lazy(() => import('@kbn/security-solution-upselling/pages/entity_analytics')) +export const EntityAnalyticsUpsellingPageLazy = withSuspenseUpsell( + lazy(() => + import('@kbn/security-solution-upselling/pages/entity_analytics').then( + ({ EntityAnalyticsUpsellingPage }) => ({ + default: EntityAnalyticsUpsellingPage, + }) + ) + ) +); + +export const EntityAnalyticsUpsellingSectionLazy = withSuspenseUpsell( + lazy(() => + import('@kbn/security-solution-upselling/sections/entity_analytics').then( + ({ EntityAnalyticsUpsellingSection }) => ({ + default: EntityAnalyticsUpsellingSection, + }) + ) + ) ); diff --git a/x-pack/plugins/security_solution_serverless/public/upselling/register_upsellings.tsx b/x-pack/plugins/security_solution_serverless/public/upselling/register_upsellings.tsx index a16bb4272f720..23c5faf1551cc 100644 --- a/x-pack/plugins/security_solution_serverless/public/upselling/register_upsellings.tsx +++ b/x-pack/plugins/security_solution_serverless/public/upselling/register_upsellings.tsx @@ -4,7 +4,14 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import type { ProductFeatureKeyType } from '@kbn/security-solution-features'; +import { ProductFeatureKey } from '@kbn/security-solution-features/keys'; import { SecurityPageName } from '@kbn/security-solution-plugin/common'; +import { + UPGRADE_INVESTIGATION_GUIDE, + UPGRADE_INVESTIGATION_GUIDE_INTERACTIONS, +} from '@kbn/security-solution-upselling/messages'; +import type { UpsellingService } from '@kbn/security-solution-upselling/service'; import type { MessageUpsellings, PageUpsellings, @@ -12,31 +19,26 @@ import type { UpsellingMessageId, UpsellingSectionId, } from '@kbn/security-solution-upselling/service/types'; -import type { UpsellingService } from '@kbn/security-solution-upselling/service'; import React from 'react'; -import { - UPGRADE_INVESTIGATION_GUIDE, - UPGRADE_INVESTIGATION_GUIDE_INTERACTIONS, -} from '@kbn/security-solution-upselling/messages'; -import { ProductFeatureKey } from '@kbn/security-solution-features/keys'; -import type { ProductFeatureKeyType } from '@kbn/security-solution-features'; -import { - EndpointAgentTamperProtectionLazy, - EndpointPolicyProtectionsLazy, - EndpointProtectionUpdatesLazy, - RuleDetailsEndpointExceptionsLazy, -} from './sections/endpoint_management'; import type { SecurityProductTypes } from '../../common/config'; import { getProductProductFeatures } from '../../common/pli/pli_features'; +import type { Services } from '../common/services'; +import { withServicesProvider } from '../common/services'; +import { getProductTypeByPLI } from './hooks/use_product_type_by_pli'; import { EndpointExceptionsDetailsUpsellingLazy, - EntityAnalyticsUpsellingLazy, + EntityAnalyticsUpsellingPageLazy, + EntityAnalyticsUpsellingSectionLazy, OsqueryResponseActionsUpsellingSectionLazy, ThreatIntelligencePaywallLazy, } from './lazy_upselling'; -import { getProductTypeByPLI } from './hooks/use_product_type_by_pli'; -import type { Services } from '../common/services'; -import { withServicesProvider } from '../common/services'; +import { + EndpointAgentTamperProtectionLazy, + EndpointPolicyProtectionsLazy, + EndpointProtectionUpdatesLazy, + RuleDetailsEndpointExceptionsLazy, +} from './sections/endpoint_management'; +import * as i18n from './translations'; interface UpsellingsConfig { pli: ProductFeatureKeyType; @@ -73,7 +75,7 @@ export const registerUpsellings = ( const upsellingSectionsToRegister = upsellingSections.reduce( (sectionUpsellings, { id, pli, component }) => { if (!enabledPLIsSet.has(pli)) { - sectionUpsellings[id] = component; + sectionUpsellings[id] = withServicesProvider(component, services); } return sectionUpsellings; }, @@ -102,8 +104,9 @@ export const upsellingPages: UpsellingPages = [ pageName: SecurityPageName.entityAnalytics, pli: ProductFeatureKey.advancedInsights, component: () => ( - ), }, @@ -123,6 +126,8 @@ export const upsellingPages: UpsellingPages = [ }, ]; +const entityAnalyticsProductType = getProductTypeByPLI(ProductFeatureKey.advancedInsights) ?? ''; + // Upselling for sections, linked by arbitrary ids export const upsellingSections: UpsellingSections = [ // It is highly advisable to make use of lazy loaded components to minimize bundle size. @@ -155,6 +160,16 @@ export const upsellingSections: UpsellingSections = [ pli: ProductFeatureKey.endpointProtectionUpdates, component: EndpointProtectionUpdatesLazy, }, + { + id: 'entity_analytics_panel', + pli: ProductFeatureKey.advancedInsights, + component: () => ( + + ), + }, ]; // Upselling for sections, linked by arbitrary ids diff --git a/x-pack/plugins/security_solution_serverless/public/upselling/translations.ts b/x-pack/plugins/security_solution_serverless/public/upselling/translations.ts new file mode 100644 index 0000000000000..971873ca77838 --- /dev/null +++ b/x-pack/plugins/security_solution_serverless/public/upselling/translations.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const UPGRADE_PRODUCT_MESSAGE = (requiredProduct: string) => + i18n.translate( + 'xpack.securitySolutionServerless.upselling.entityAnalytics.upgradeProductMessage', + { + defaultMessage: + 'Entity risk scoring capability is available in our {requiredProduct} license tier', + values: { + requiredProduct, + }, + } + ); 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 db4af56993d76..20a48b3e3076d 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 @@ -13,9 +13,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiText, - EuiCallOut, } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; import { ConnectorStatus } from '@kbn/search-connectors'; import React from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -77,18 +75,6 @@ export const ConnectionDetails: React.FC = ({ {elasticsearchUrl} - {status === ConnectorStatus.CREATED && ( - <> - - - - )} ); }; diff --git a/x-pack/plugins/serverless_search/public/application/components/connectors/connector_config/connector_link.tsx b/x-pack/plugins/serverless_search/public/application/components/connectors/connector_config/connector_link.tsx index b0d1b412526ca..29bbc55d4cd71 100644 --- a/x-pack/plugins/serverless_search/public/application/components/connectors/connector_config/connector_link.tsx +++ b/x-pack/plugins/serverless_search/public/application/components/connectors/connector_config/connector_link.tsx @@ -5,7 +5,15 @@ * 2.0. */ -import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui'; +import { + EuiButton, + EuiCallOut, + EuiFlexGroup, + EuiFlexItem, + EuiSpacer, + EuiText, + EuiTitle, +} from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ConnectorStatus } from '@kbn/search-connectors'; import React from 'react'; @@ -82,6 +90,18 @@ export const ConnectorLinkElasticsearch: React.FC + + {status === ConnectorStatus.CREATED ? ( + + + + ) : null} ); diff --git a/x-pack/plugins/serverless_search/public/application/components/connectors/connectors_table.tsx b/x-pack/plugins/serverless_search/public/application/components/connectors/connectors_table.tsx index 5efbb9dfb5b9c..6f8dbd0edb4bc 100644 --- a/x-pack/plugins/serverless_search/public/application/components/connectors/connectors_table.tsx +++ b/x-pack/plugins/serverless_search/public/application/components/connectors/connectors_table.tsx @@ -38,7 +38,6 @@ import React, { useEffect, useState } from 'react'; import { generatePath } from 'react-router-dom'; import { CONNECTORS_LABEL, - CONNECTOR_LABEL, COPY_CONNECTOR_ID_LABEL, DELETE_CONNECTOR_LABEL, } from '../../../../common/i18n_string'; @@ -256,8 +255,8 @@ export const ConnectorsTable: React.FC = () => { connectors: {CONNECTORS_LABEL}, items: ( - - - + - + ), count: , @@ -297,7 +296,7 @@ const DeleteConnectorModalAction: React.FC<{ connector: Connector }> = ({ connec setModalIsOpen(false)} connectorId={connector.id} - connectorName={connector.name || CONNECTOR_LABEL} + connectorName={connector.name} /> )} diff --git a/x-pack/plugins/serverless_search/public/application/components/connectors/delete_connector_modal.tsx b/x-pack/plugins/serverless_search/public/application/components/connectors/delete_connector_modal.tsx index a6ce7b225e6f0..cab4ffabdf9cf 100644 --- a/x-pack/plugins/serverless_search/public/application/components/connectors/delete_connector_modal.tsx +++ b/x-pack/plugins/serverless_search/public/application/components/connectors/delete_connector_modal.tsx @@ -19,6 +19,10 @@ interface DeleteConnectorModalProps { onSuccess?: () => void; } +const DELETE_LABEL = i18n.translate('xpack.serverlessSearch.connectors.deleteModal.deleteLabel', { + defaultMessage: 'DELETE', +}); + export const DeleteConnectorModal: React.FC = ({ connectorId, connectorName, @@ -50,7 +54,7 @@ export const DeleteConnectorModal: React.FC = ({ { closeDeleteModal(); @@ -70,12 +74,12 @@ export const DeleteConnectorModal: React.FC = ({ confirmButtonText={i18n.translate( 'xpack.serverlessSearch.connectors.deleteModal.confirmButton.title', { - defaultMessage: 'Delete index', + defaultMessage: 'Delete connector', } )} defaultFocusedButton="confirm" buttonColor="danger" - confirmButtonDisabled={inputConnectorName.trim() !== connectorName} + confirmButtonDisabled={inputConnectorName.trim() !== (connectorName || DELETE_LABEL)} isLoading={isLoading} >

@@ -83,7 +87,7 @@ export const DeleteConnectorModal: React.FC = ({ 'xpack.serverlessSearch.connectors.deleteModal.syncsWarning.connectorNameDescription', { defaultMessage: 'This action cannot be undone. Please type {connectorName} to confirm.', - values: { connectorName }, + values: { connectorName: connectorName || DELETE_LABEL }, } )}

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 927d3d795aaed..fcd67f30c4b59 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 @@ -103,7 +103,7 @@ export const EditConnector: React.FC = () => { setDeleteModalIsOpen(false)} connectorId={connector.id} - connectorName={connector.name || CONNECTOR_LABEL} + connectorName={connector.name} onSuccess={() => navigateToUrl('./')} /> )} diff --git a/x-pack/plugins/serverless_search/public/application/components/connectors/edit_name.tsx b/x-pack/plugins/serverless_search/public/application/components/connectors/edit_name.tsx index 85f7a097cb089..b81fc51b07bcf 100644 --- a/x-pack/plugins/serverless_search/public/application/components/connectors/edit_name.tsx +++ b/x-pack/plugins/serverless_search/public/application/components/connectors/edit_name.tsx @@ -48,7 +48,7 @@ export const EditName: React.FC = ({ connector }) => { }, onSuccess: (successData) => { queryClient.setQueryData(queryKey, { - connector: { ...connector, service_type: successData }, + connector: { ...connector, name: successData }, }); queryClient.invalidateQueries(queryKey); setIsEditing(false); diff --git a/x-pack/plugins/serverless_search/public/application/components/connectors/edit_service_type.tsx b/x-pack/plugins/serverless_search/public/application/components/connectors/edit_service_type.tsx index 0c7cfab2eca42..fe4b6bd7e9768 100644 --- a/x-pack/plugins/serverless_search/public/application/components/connectors/edit_service_type.tsx +++ b/x-pack/plugins/serverless_search/public/application/components/connectors/edit_service_type.tsx @@ -76,6 +76,8 @@ export const EditServiceType: React.FC = ({ connector }) = })} mutate(event)} diff --git a/x-pack/plugins/serverless_search/public/application/components/connectors_overview.tsx b/x-pack/plugins/serverless_search/public/application/components/connectors_overview.tsx index ed347e36e7738..26f7a85716a2d 100644 --- a/x-pack/plugins/serverless_search/public/application/components/connectors_overview.tsx +++ b/x-pack/plugins/serverless_search/public/application/components/connectors_overview.tsx @@ -44,7 +44,7 @@ export const ConnectorsOverview = () => { data-test-subj="serverlessSearchConnectorsTitle" restrictWidth rightSideItems={[ - + { +export const useConnectors = () => { const { http } = useKibanaServices(); return useQuery({ - queryKey: ['fetchConnectors', from, size], + queryKey: ['fetchConnectors'], queryFn: () => - http.fetch<{ connectors: Connector[] }>('/internal/serverless_search/connectors', { - query: { from, size }, - }), + http.fetch<{ connectors: Connector[] }>('/internal/serverless_search/connectors'), }); }; diff --git a/x-pack/plugins/stack_connectors/common/crowdstrike/constants.ts b/x-pack/plugins/stack_connectors/common/crowdstrike/constants.ts index 3b547dba35926..c221d74c3b8a0 100644 --- a/x-pack/plugins/stack_connectors/common/crowdstrike/constants.ts +++ b/x-pack/plugins/stack_connectors/common/crowdstrike/constants.ts @@ -12,4 +12,5 @@ export const API_MAX_RESULTS = 1000; export enum SUB_ACTION { GET_AGENT_DETAILS = 'getAgentDetails', HOST_ACTIONS = 'hostActions', + GET_AGENT_ONLINE_STATUS = 'getAgentOnlineStatus', } diff --git a/x-pack/plugins/stack_connectors/common/crowdstrike/schema.ts b/x-pack/plugins/stack_connectors/common/crowdstrike/schema.ts index 559aebfc7fa39..d19deabd6aeda 100644 --- a/x-pack/plugins/stack_connectors/common/crowdstrike/schema.ts +++ b/x-pack/plugins/stack_connectors/common/crowdstrike/schema.ts @@ -17,6 +17,7 @@ export const CrowdstrikeSecretsSchema = schema.object({ clientSecret: schema.string(), }); +export const RelaxedCrowdstrikeBaseApiResponseSchema = schema.object({}, { unknowns: 'allow' }); export const CrowdstrikeBaseApiResponseSchema = schema.object( { resources: schema.arrayOf(schema.any()), @@ -33,44 +34,85 @@ export const CrowdstrikeBaseApiResponseSchema = schema.object( { unknowns: 'allow' } ); +export const CrowdstrikeGetAgentOnlineStatusResponseSchema = schema.object( + { + resources: schema.arrayOf( + schema.object( + { + state: schema.maybe(schema.string()), + id: schema.maybe(schema.string()), + }, + { unknowns: 'allow' } + ) + ), + errors: schema.nullable(schema.arrayOf(schema.any())), + meta: schema.object( + { + query_time: schema.maybe(schema.number()), + powered_by: schema.maybe(schema.string()), + trace_id: schema.maybe(schema.string()), + }, + { unknowns: 'allow' } + ), + }, + { unknowns: 'allow' } +); + export const CrowdstrikeGetAgentsResponseSchema = schema.object( { resources: schema.arrayOf( - schema.arrayOf( - schema.object( - { - device_id: schema.maybe(schema.string()), - cid: schema.maybe(schema.string()), - agent_load_flags: schema.maybe(schema.string()), - agent_local_time: schema.maybe(schema.string()), - agent_version: schema.maybe(schema.string()), - bios_manufacturer: schema.maybe(schema.string()), - bios_version: schema.maybe(schema.string()), - config_id_base: schema.maybe(schema.string()), - config_id_build: schema.maybe(schema.string()), - config_id_platform: schema.maybe(schema.string()), - cpu_signature: schema.maybe(schema.string()), - cpu_vendor: schema.maybe(schema.string()), - external_ip: schema.maybe(schema.string()), - mac_address: schema.maybe(schema.string()), - instance_id: schema.maybe(schema.string()), - service_provider: schema.maybe(schema.string()), - service_provider_account_id: schema.maybe(schema.string()), - hostname: schema.maybe(schema.string()), - first_seen: schema.maybe(schema.string()), - last_login_timestamp: schema.maybe(schema.string()), - last_login_user: schema.maybe(schema.string()), - last_login_uid: schema.maybe(schema.string()), - last_seen: schema.maybe(schema.string()), - local_ip: schema.maybe(schema.string()), - major_version: schema.maybe(schema.string()), - minor_version: schema.maybe(schema.string()), - os_version: schema.maybe(schema.string()), - platform_id: schema.maybe(schema.string()), - platform_name: schema.maybe(schema.string()), - policies: schema.maybe( - schema.arrayOf( - schema.object( + schema.object( + { + device_id: schema.maybe(schema.string()), + cid: schema.maybe(schema.string()), + agent_load_flags: schema.maybe(schema.string()), + agent_local_time: schema.maybe(schema.string()), + agent_version: schema.maybe(schema.string()), + bios_manufacturer: schema.maybe(schema.string()), + bios_version: schema.maybe(schema.string()), + config_id_base: schema.maybe(schema.string()), + config_id_build: schema.maybe(schema.string()), + config_id_platform: schema.maybe(schema.string()), + cpu_signature: schema.maybe(schema.string()), + cpu_vendor: schema.maybe(schema.string()), + external_ip: schema.maybe(schema.string()), + mac_address: schema.maybe(schema.string()), + instance_id: schema.maybe(schema.string()), + service_provider: schema.maybe(schema.string()), + service_provider_account_id: schema.maybe(schema.string()), + hostname: schema.maybe(schema.string()), + first_seen: schema.maybe(schema.string()), + last_login_timestamp: schema.maybe(schema.string()), + last_login_user: schema.maybe(schema.string()), + last_login_uid: schema.maybe(schema.string()), + last_seen: schema.maybe(schema.string()), + local_ip: schema.maybe(schema.string()), + major_version: schema.maybe(schema.string()), + minor_version: schema.maybe(schema.string()), + os_version: schema.maybe(schema.string()), + platform_id: schema.maybe(schema.string()), + platform_name: schema.maybe(schema.string()), + policies: schema.maybe( + schema.arrayOf( + schema.object( + { + policy_type: schema.maybe(schema.string()), + policy_id: schema.maybe(schema.string()), + applied: schema.maybe(schema.boolean()), + settings_hash: schema.maybe(schema.string()), + assigned_date: schema.maybe(schema.string()), + applied_date: schema.maybe(schema.string()), + rule_groups: schema.maybe(schema.any()), + }, + { unknowns: 'allow' } + ) + ) + ), + reduced_functionality_mode: schema.maybe(schema.string()), + device_policies: schema.maybe( + schema.object( + { + prevention: schema.object( { policy_type: schema.maybe(schema.string()), policy_id: schema.maybe(schema.string()), @@ -81,94 +123,75 @@ export const CrowdstrikeGetAgentsResponseSchema = schema.object( rule_groups: schema.maybe(schema.any()), }, { unknowns: 'allow' } - ) - ) - ), - reduced_functionality_mode: schema.maybe(schema.string()), - device_policies: schema.maybe( - schema.object( - { - prevention: schema.object( - { - policy_type: schema.maybe(schema.string()), - policy_id: schema.maybe(schema.string()), - applied: schema.maybe(schema.boolean()), - settings_hash: schema.maybe(schema.string()), - assigned_date: schema.maybe(schema.string()), - applied_date: schema.maybe(schema.string()), - rule_groups: schema.any(), - }, - { unknowns: 'allow' } - ), - sensor_update: schema.object( - { - policy_type: schema.maybe(schema.string()), - policy_id: schema.maybe(schema.string()), - applied: schema.maybe(schema.boolean()), - settings_hash: schema.maybe(schema.string()), - assigned_date: schema.maybe(schema.string()), - applied_date: schema.maybe(schema.string()), - uninstall_protection: schema.maybe(schema.string()), - }, - { unknowns: 'allow' } - ), - global_config: schema.object( - { - policy_type: schema.maybe(schema.string()), - policy_id: schema.maybe(schema.string()), - applied: schema.maybe(schema.boolean()), - settings_hash: schema.maybe(schema.string()), - assigned_date: schema.maybe(schema.string()), - applied_date: schema.maybe(schema.string()), - }, - { unknowns: 'allow' } - ), - remote_response: schema.object( - { - policy_type: schema.maybe(schema.string()), - policy_id: schema.maybe(schema.string()), - applied: schema.maybe(schema.boolean()), - settings_hash: schema.maybe(schema.string()), - assigned_date: schema.maybe(schema.string()), - applied_date: schema.maybe(schema.string()), - }, - { unknowns: 'allow' } - ), - }, - { unknowns: 'allow' } - ) - ), - groups: schema.maybe(schema.arrayOf(schema.any())), - group_hash: schema.maybe(schema.string()), - product_type_desc: schema.maybe(schema.string()), - provision_status: schema.maybe(schema.string()), - serial_number: schema.maybe(schema.string()), - status: schema.maybe(schema.string()), - system_manufacturer: schema.maybe(schema.string()), - system_product_name: schema.maybe(schema.string()), - tags: schema.maybe(schema.arrayOf(schema.any())), - modified_timestamp: schema.any(), - meta: schema.maybe( - schema.object( - { - version: schema.maybe(schema.string()), - version_string: schema.maybe(schema.string()), - }, - { unknowns: 'allow' } - ) - ), - zone_group: schema.maybe(schema.string()), - kernel_version: schema.maybe(schema.string()), - chassis_type: schema.maybe(schema.string()), - chassis_type_desc: schema.maybe(schema.string()), - connection_ip: schema.maybe(schema.string()), - default_gateway_ip: schema.maybe(schema.string()), - connection_mac_address: schema.maybe(schema.string()), - linux_sensor_mode: schema.maybe(schema.string()), - deployment_type: schema.maybe(schema.string()), - }, - { unknowns: 'allow' } - ) + ), + sensor_update: schema.object( + { + policy_type: schema.maybe(schema.string()), + policy_id: schema.maybe(schema.string()), + applied: schema.maybe(schema.boolean()), + settings_hash: schema.maybe(schema.string()), + assigned_date: schema.maybe(schema.string()), + applied_date: schema.maybe(schema.string()), + uninstall_protection: schema.maybe(schema.string()), + }, + { unknowns: 'allow' } + ), + global_config: schema.object( + { + policy_type: schema.maybe(schema.string()), + policy_id: schema.maybe(schema.string()), + applied: schema.maybe(schema.boolean()), + settings_hash: schema.maybe(schema.string()), + assigned_date: schema.maybe(schema.string()), + applied_date: schema.maybe(schema.string()), + }, + { unknowns: 'allow' } + ), + remote_response: schema.object( + { + policy_type: schema.maybe(schema.string()), + policy_id: schema.maybe(schema.string()), + applied: schema.maybe(schema.boolean()), + settings_hash: schema.maybe(schema.string()), + assigned_date: schema.maybe(schema.string()), + applied_date: schema.maybe(schema.string()), + }, + { unknowns: 'allow' } + ), + }, + { unknowns: 'allow' } + ) + ), + groups: schema.maybe(schema.arrayOf(schema.any())), + group_hash: schema.maybe(schema.string()), + product_type_desc: schema.maybe(schema.string()), + provision_status: schema.maybe(schema.string()), + serial_number: schema.maybe(schema.string()), + status: schema.maybe(schema.string()), + system_manufacturer: schema.maybe(schema.string()), + system_product_name: schema.maybe(schema.string()), + tags: schema.maybe(schema.arrayOf(schema.any())), + modified_timestamp: schema.any(), + meta: schema.maybe( + schema.object( + { + version: schema.maybe(schema.string()), + version_string: schema.maybe(schema.string()), + }, + { unknowns: 'allow' } + ) + ), + zone_group: schema.maybe(schema.string()), + kernel_version: schema.maybe(schema.string()), + chassis_type: schema.maybe(schema.string()), + chassis_type_desc: schema.maybe(schema.string()), + connection_ip: schema.maybe(schema.string()), + default_gateway_ip: schema.maybe(schema.string()), + connection_mac_address: schema.maybe(schema.string()), + linux_sensor_mode: schema.maybe(schema.string()), + deployment_type: schema.maybe(schema.string()), + }, + { unknowns: 'allow' } ) ), errors: schema.nullable(schema.arrayOf(schema.any())), diff --git a/x-pack/plugins/stack_connectors/common/crowdstrike/types.ts b/x-pack/plugins/stack_connectors/common/crowdstrike/types.ts index e9d6448db9231..c0f98ee1b90a1 100644 --- a/x-pack/plugins/stack_connectors/common/crowdstrike/types.ts +++ b/x-pack/plugins/stack_connectors/common/crowdstrike/types.ts @@ -10,20 +10,28 @@ import { CrowdstrikeBaseApiResponseSchema, CrowdstrikeConfigSchema, CrowdstrikeGetAgentsParamsSchema, - CrowdstrikeGetAgentsResponseSchema, + CrowdstrikeGetAgentOnlineStatusResponseSchema, CrowdstrikeHostActionsParamsSchema, CrowdstrikeSecretsSchema, CrowdstrikeActionParamsSchema, CrowdstrikeGetTokenResponseSchema, + CrowdstrikeGetAgentsResponseSchema, + RelaxedCrowdstrikeBaseApiResponseSchema, } from './schema'; export type CrowdstrikeConfig = TypeOf; export type CrowdstrikeSecrets = TypeOf; export type CrowdstrikeBaseApiResponse = TypeOf; +export type RelaxedCrowdstrikeBaseApiResponse = TypeOf< + typeof RelaxedCrowdstrikeBaseApiResponseSchema +>; export type CrowdstrikeGetAgentsParams = Partial>; export type CrowdstrikeGetAgentsResponse = TypeOf; +export type CrowdstrikeGetAgentOnlineStatusResponse = TypeOf< + typeof CrowdstrikeGetAgentOnlineStatusResponseSchema +>; export type CrowdstrikeGetTokenResponse = TypeOf; export type CrowdstrikeHostActionsParams = TypeOf; diff --git a/x-pack/plugins/stack_connectors/common/openai/schema.ts b/x-pack/plugins/stack_connectors/common/openai/schema.ts index 9c64a4a7514c4..f62ee1f35174c 100644 --- a/x-pack/plugins/stack_connectors/common/openai/schema.ts +++ b/x-pack/plugins/stack_connectors/common/openai/schema.ts @@ -148,7 +148,8 @@ export const RunActionResponseSchema = schema.object( message: schema.object( { role: schema.string(), - content: schema.maybe(schema.string()), + // nullable because message can contain function calls instead of final response when used with RAG + content: schema.maybe(schema.nullable(schema.string())), }, { unknowns: 'ignore' } ), diff --git a/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.test.ts index b89c486d0a4a0..9eb1444c9bc0d 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.test.ts @@ -13,6 +13,7 @@ import { CROWDSTRIKE_CONNECTOR_ID } from '../../../public/common'; const tokenPath = 'https://api.crowdstrike.com/oauth2/token'; const hostPath = 'https://api.crowdstrike.com/devices/entities/devices/v2'; +const onlineStatusPath = 'https://api.crowdstrike.com/devices/entities/online-state/v1'; const actionsPath = 'https://api.crowdstrike.com/devices/entities/devices-actions/v2'; describe('CrowdstrikeConnector', () => { const connector = new CrowdstrikeConnector({ @@ -113,6 +114,45 @@ describe('CrowdstrikeConnector', () => { }); }); + describe('getAgentOnlineStatus', () => { + it('should make a GET request to the correct URL with correct params', async () => { + const mockResponse = { data: { resources: [{}] } }; + + mockedRequest.mockResolvedValueOnce({ data: { access_token: 'testToken' } }); + mockedRequest.mockResolvedValueOnce(mockResponse); + + const result = await connector.getAgentOnlineStatus({ ids: ['id1', 'id2'] }); + + expect(mockedRequest).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + headers: { + accept: 'application/json', + 'Content-Type': 'application/x-www-form-urlencoded', + authorization: expect.any(String), + }, + method: 'post', + responseSchema: expect.any(Object), + url: tokenPath, + }) + ); + expect(mockedRequest).toHaveBeenNthCalledWith( + 2, + expect.objectContaining({ + headers: expect.objectContaining({ + Authorization: 'Bearer testToken', + }), + method: 'GET', + params: { ids: ['id1', 'id2'] }, + paramsSerializer: expect.any(Function), + responseSchema: expect.any(Object), + url: onlineStatusPath, + }) + ); + expect(result).toEqual({ resources: [{}] }); + }); + }); + describe('getTokenRequest', () => { it('should make a POST request to the correct URL with correct headers', async () => { const mockResponse = { data: { access_token: 'testToken' } }; @@ -191,7 +231,6 @@ describe('CrowdstrikeConnector', () => { mockedRequest.mockResolvedValueOnce({ data: { access_token: 'testToken' } }); mockedRequest.mockRejectedValueOnce(mockResponse); - // expect(mockedRequest).toThrowError('access denied, invalid bearer token'); await expect(() => connector.getAgentDetails({ ids: ['id1', 'id2'] })).rejects.toThrowError( 'something goes wrong' ); @@ -203,7 +242,6 @@ describe('CrowdstrikeConnector', () => { mockedRequest.mockResolvedValueOnce({ data: { access_token: 'testToken' } }); mockedRequest.mockRejectedValueOnce(mockResponse); - // expect(mockedRequest).toThrowError('access denied, invalid bearer token'); await expect(() => connector.getAgentDetails({ ids: ['id1', 'id2'] })).rejects.toThrowError(); expect(mockedRequest).toHaveBeenCalledTimes(3); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.ts b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.ts index 583aa68ddb4be..6a758a9d33117 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.ts @@ -6,6 +6,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 type { @@ -13,16 +14,17 @@ import type { CrowdstrikeSecrets, CrowdstrikeGetAgentsResponse, CrowdstrikeGetAgentsParams, - CrowdstrikeBaseApiResponse, CrowdstrikeHostActionsParams, CrowdstrikeGetTokenResponse, + CrowdstrikeGetAgentOnlineStatusResponse, + RelaxedCrowdstrikeBaseApiResponse, } from '../../../common/crowdstrike/types'; import { - CrowdstrikeGetAgentsResponseSchema, CrowdstrikeHostActionsParamsSchema, CrowdstrikeGetAgentsParamsSchema, CrowdstrikeGetTokenResponseSchema, CrowdstrikeHostActionsResponseSchema, + RelaxedCrowdstrikeBaseApiResponseSchema, } from '../../../common/crowdstrike/schema'; import { SUB_ACTION } from '../../../common/crowdstrike/constants'; import { CrowdstrikeError } from './error'; @@ -52,6 +54,7 @@ export class CrowdstrikeConnector extends SubActionConnector< getToken: string; agents: string; hostAction: string; + agentStatus: string; }; constructor(params: ServiceParams) { @@ -60,6 +63,7 @@ export class CrowdstrikeConnector extends SubActionConnector< getToken: `${this.config.url}/oauth2/token`, hostAction: `${this.config.url}/devices/entities/devices-actions/v2`, agents: `${this.config.url}/devices/entities/devices/v2`, + agentStatus: `${this.config.url}/devices/entities/online-state/v1`, }; if (!CrowdstrikeConnector.base64encodedToken) { @@ -83,6 +87,12 @@ export class CrowdstrikeConnector extends SubActionConnector< method: 'executeHostActions', schema: CrowdstrikeHostActionsParamsSchema, }); + + this.registerSubAction({ + name: SUB_ACTION.GET_AGENT_ONLINE_STATUS, + method: 'getAgentOnlineStatus', + schema: CrowdstrikeGetAgentsParamsSchema, + }); } public async executeHostActions({ alertIds, ...payload }: CrowdstrikeHostActionsParams) { @@ -118,8 +128,22 @@ export class CrowdstrikeConnector extends SubActionConnector< ids: payload.ids, }, paramsSerializer, - responseSchema: CrowdstrikeGetAgentsResponseSchema, - }); + responseSchema: RelaxedCrowdstrikeBaseApiResponseSchema, + }) as Promise; + } + + public async getAgentOnlineStatus( + payload: CrowdstrikeGetAgentsParams + ): Promise { + return this.crowdstrikeApiRequest({ + url: this.urls.agentStatus, + method: 'GET', + params: { + ids: payload.ids, + }, + paramsSerializer, + responseSchema: RelaxedCrowdstrikeBaseApiResponseSchema, + }) as Promise; } private async getTokenRequest() { @@ -146,7 +170,7 @@ export class CrowdstrikeConnector extends SubActionConnector< return token; } - private async crowdstrikeApiRequest( + private async crowdstrikeApiRequest( req: SubActionRequestParams, retried?: boolean ): Promise { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.ts b/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.ts index bab615cbf7e58..544b6bf7092c2 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.ts @@ -319,6 +319,7 @@ export class OpenAIConnector extends SubActionConnector { * Non-streamed security solution AI Assistant requests * Responsible for invoking the runApi method with the provided body. * It then formats the response into a string + * To use function calling, call the run subaction directly * @param body - the OpenAI chat completion request body * @returns an object with the response string and the usage object */ diff --git a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json index 7fbce312fde18..90aab7f2552fb 100644 --- a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @@ -9782,6 +9782,18 @@ "description": "The total number of enrolled Fleet Server agents currently offline" } }, + "inactive": { + "type": "long", + "_meta": { + "description": "The total number of enrolled Fleet Server agents currently inactive" + } + }, + "unenrolled": { + "type": "long", + "_meta": { + "description": "The total number of unenrolled Fleet Server agents" + } + }, "num_host_urls": { "type": "long", "_meta": { diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 017acbe370416..83548c6a562fd 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -686,7 +686,6 @@ "core.deprecations.elasticsearchUsername.manualSteps2": "Ajoutez le paramètre \"elasticsearch.serviceAccountToken\" à kibana.yml.", "core.deprecations.elasticsearchUsername.manualSteps3": "Supprimez \"elasticsearch.username\" et \"elasticsearch.password\" de kibana.yml.", "core.deprecations.noCorrectiveAction": "Ce déclassement ne peut pas être résolu automatiquement.", - "core.euiAbsoluteTab.dateFormatHint": "Appuyez sur la touche Entrée pour analyser l'élément en tant que date.", "core.euiAccordionChildrenLoading.message": "Chargement", "core.euiAutoRefresh.autoRefreshLabel": "Actualisation automatique", "core.euiAutoRefresh.buttonLabelOff": "L'actualisation automatique est désactivée", @@ -5880,8 +5879,6 @@ "securitySolutionPackages.ecsDataQualityDashboard.unmanagedPatternTooltip": "{indices} {indices, plural, =1 {L'index correspondant} other {Les index correspondants}} au modèle {pattern} {indices, plural, =1 {n'est pas géré} other {ne sont pas gérés}} par la gestion du cycle de vie des index (ILM)", "securitySolutionPackages.ecsDataQualityDashboard.warmPatternTooltip": "{indices} {indices, plural, =1 {L'index correspondant} other {Les index correspondants}} au modèle {pattern} {indices, plural, =1 {est} other {sont}} \"warm\". Les index \"warm\" ne sont plus mis à jour, mais ils sont toujours interrogés.", "securitySolutionPackages.entityAnalytics.paywall.upgradeButton": "Passer à {requiredLicenseOrProduct}", - "securitySolutionPackages.entityAnalytics.paywall.upgradeLicenseMessage": "Cette fonctionnalité est disponible avec l'abonnement {requiredLicense} ou supérieur", - "securitySolutionPackages.entityAnalytics.paywall.upgradeProductMessage": "La capacité d'évaluation du risque des entités est disponible dans notre niveau de licence {requiredProduct}", "securitySolutionPackages.markdown.insight.upsell": "Passez au niveau {requiredLicense} pour pouvoir utiliser les informations des guides d'investigation", "securitySolutionPackages.alertSuppressionRuleDetails.upsell": "La suppression d'alertes est configurée mais elle ne sera pas appliquée en raison d'une licence insuffisante", "securitySolutionPackages.beta.label": "Bêta", @@ -6793,7 +6790,6 @@ "unifiedFieldList.fieldStats.filterOutValueButtonAriaLabel": "Exclure le {field} : \"{value}\"", "unifiedFieldList.fieldStats.filterValueButtonAriaLabel": "Filtrer sur le {field} : \"{value}\"", "unifiedFieldList.fieldStats.noFieldDataInSampleDescription": "Aucune donnée de champ pour {sampledDocumentsFormatted} {sampledDocuments, plural, one {exemple d'enregistrement} other {exemples d'enregistrement}}.", - "unifiedFieldList.fieldCategorizeButton.label": "Exécuter l'analyse du modèle", "unifiedFieldList.fieldItemButton.mappingConflictDescription": "Ce champ est défini avec plusieurs types (chaîne, entier, etc.) dans les différents index qui correspondent à ce modèle. Vous pouvez toujours utiliser ce champ conflictuel, mais il sera indisponible pour les fonctions qui nécessitent que Kibana en connaisse le type. Pour corriger ce problème, vous devrez réindexer vos données.", "unifiedFieldList.fieldItemButton.mappingConflictTitle": "Conflit de mapping", "unifiedFieldList.fieldList.noFieldsCallout.noDataLabel": "Aucun champ.", @@ -12930,20 +12926,6 @@ "xpack.csp.findings.findingsFlyout.ruleTab.tagsTitle": "Balises", "xpack.csp.findings.findingsFlyout.ruleTabTitle": "Règle", "xpack.csp.findings.findingsFlyout.tableTabTitle": "Tableau", - "xpack.csp.findings.findingsTable.findingsTableColumn.lastCheckedColumnLabel": "Dernière vérification", - "xpack.csp.findings.findingsTable.findingsTableColumn.packageFixedVersionColumnLabel": "Version du correctif", - "xpack.csp.findings.findingsTable.findingsTableColumn.packageNameColumnLabel": "Pack", - "xpack.csp.findings.findingsTable.findingsTableColumn.packageVersionColumnLabel": "Version", - "xpack.csp.findings.findingsTable.findingsTableColumn.resourceIdColumnLabel": "ID ressource", - "xpack.csp.findings.findingsTable.findingsTableColumn.resourceNameColumnLabel": "Nom de ressource", - "xpack.csp.findings.findingsTable.findingsTableColumn.resourceTypeColumnLabel": "Type de ressource", - "xpack.csp.findings.findingsTable.findingsTableColumn.resultColumnLabel": "Résultat", - "xpack.csp.findings.findingsTable.findingsTableColumn.ruleNameColumnLabel": "Nom de règle", - "xpack.csp.findings.findingsTable.findingsTableColumn.ruleNumberColumnLabel": "Numéro de règle", - "xpack.csp.findings.findingsTable.findingsTableColumn.ruleSectionColumnLabel": "Section CIS", - "xpack.csp.findings.findingsTable.findingsTableColumn.vulnerabilityIdColumnLabel": "Vulnérabilité", - "xpack.csp.findings.findingsTable.findingsTableColumn.vulnerabilityScoreColumnLabel": "CVSS", - "xpack.csp.findings.findingsTable.findingsTableColumn.vulnerabilitySeverityColumnLabel": "Sévérité", "xpack.csp.findings.gcpIntegration.gcpInputText.credentialFileText": "Chemin vers le fichier JSON qui contient les informations d'identification et la clé utilisés pour souscrire", "xpack.csp.findings.gcpIntegration.gcpInputText.credentialJSONText": "Blob JSON qui contient les informations d'identification et la clé utilisées pour souscrire", "xpack.csp.findings.gcpIntegration.gcpInputText.credentialSelectBoxTitle": "Informations d'identification", @@ -13595,7 +13577,6 @@ "xpack.elasticAssistant.assistant.content.prompts.system.ifYouDontKnowTheAnswer": "Ne répondez pas aux questions qui ne sont pas liées à Elastic Security.", "xpack.elasticAssistant.assistant.content.prompts.system.superheroPersonality": "Donnez la réponse la plus pertinente et détaillée possible, comme si vous deviez communiquer ces informations à un expert en cybersécurité.", "xpack.elasticAssistant.assistant.content.prompts.system.superheroSystemPromptName": "Invite système améliorée", - "xpack.elasticAssistant.assistant.content.prompts.system.useTheFollowingContextToAnswer": "Utilisez le contexte suivant pour répondre aux questions :", "xpack.elasticAssistant.assistant.content.prompts.system.youAreAHelpfulExpertAssistant": "Vous êtes un assistant expert et serviable qui répond à des questions au sujet d’Elastic Security.", "xpack.elasticAssistant.assistant.content.prompts.user.finallySuggestInvestigationGuideAndFormatAsMarkdown": "Ajoutez votre description, les actions que vous recommandez ainsi que les étapes de triage à puces. Utilisez les données \"MITRE ATT&CK\" fournies pour ajouter du contexte et des recommandations de MITRE ainsi que des liens hypertexte vers les pages pertinentes sur le site web de MITRE. Assurez-vous d’inclure les scores de risque de l’utilisateur et de l’hôte du contexte. Votre réponse doit inclure des étapes qui pointent vers les fonctionnalités spécifiques d’Elastic Security, y compris les actions de réponse du terminal, l’intégration OSQuery Manager d’Elastic Agent (avec des exemples de requêtes OSQuery), des analyses de timeline et d’entités, ainsi qu’un lien pour toute la documentation Elastic Security pertinente.", "xpack.elasticAssistant.assistant.content.prompts.user.thenSummarizeSuggestedKqlAndEqlQueries": "Évaluer l’événement depuis le contexte ci-dessus et formater soigneusement la sortie en syntaxe Markdown pour mon cas Elastic Security.", @@ -18596,7 +18577,6 @@ "xpack.fleet.fleetServerSetup.addFleetServerHostButton": "Ajouter un hôte", "xpack.fleet.fleetServerSetup.addFleetServerHostStepTitle": "Ajouter l'hôte de votre serveur Fleet", "xpack.fleet.fleetServerSetup.addFleetServerHostSuccessTitle": "Hôte du serveur Fleet ajouté", - "xpack.fleet.fleetServerSetup.calloutTitle": "Diagnostic de l'agent", "xpack.fleet.fleetServerSetup.cloudDeploymentLink": "Modifier le déploiement", "xpack.fleet.fleetServerSetup.cloudSetupTitle": "Activer un serveur Fleet", "xpack.fleet.fleetServerSetup.errorAddingFleetServerHostTitle": "Erreur lors de l'ajout de l'hôte du serveur Fleet", @@ -33590,7 +33570,6 @@ "xpack.securitySolution.assistant.content.prompts.system.outputFormatting": "Si vous répondez à une question liée à KQL, à EQL, ou à ES|QL, la réponse doit être immédiatement utilisable dans une chronologie d'Elastic Security ; veuillez toujours formater correctement la sortie avec des accents graves. Toute réponse à une requête DSL doit aussi être utilisable dans une chronologie de sécurité. Cela signifie que vous ne devez inclure que la portion \"filtre\" de la requête.", "xpack.securitySolution.assistant.content.prompts.system.superheroPersonality": "Donnez la réponse la plus pertinente et détaillée possible, comme si vous deviez communiquer ces informations à un expert en cybersécurité.", "xpack.securitySolution.assistant.content.prompts.system.superheroSystemPromptName": "Invite système améliorée", - "xpack.securitySolution.assistant.content.prompts.system.useTheFollowingContextToAnswer": "Utilisez le contexte suivant pour répondre aux questions :", "xpack.securitySolution.assistant.content.prompts.system.youAreAHelpfulExpertAssistant": "Vous êtes un assistant expert et serviable qui répond à des questions au sujet d’Elastic Security.", "xpack.securitySolution.assistant.content.prompts.user.finallySuggestInvestigationGuideAndFormatAsMarkdown": "Ajoutez votre description, les actions que vous recommandez ainsi que les étapes de triage à puces. Utilisez les données \"MITRE ATT&CK\" fournies pour ajouter du contexte et des recommandations de MITRE ainsi que des liens hypertexte vers les pages pertinentes sur le site web de MITRE. Assurez-vous d’inclure les scores de risque de l’utilisateur et de l’hôte du contexte. Votre réponse doit inclure des étapes qui pointent vers les fonctionnalités spécifiques d’Elastic Security, y compris les actions de réponse du terminal, l’intégration OSQuery Manager d’Elastic Agent (avec des exemples de requêtes OSQuery), des analyses de timeline et d’entités, ainsi qu’un lien pour toute la documentation Elastic Security pertinente.", "xpack.securitySolution.assistant.content.prompts.user.thenSummarizeSuggestedKqlAndEqlQueries": "Évaluer l’événement depuis le contexte ci-dessus et formater soigneusement la sortie en syntaxe Markdown pour mon cas Elastic Security.", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index f03111faf3bd1..7aad465a0b280 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -686,7 +686,6 @@ "core.deprecations.elasticsearchUsername.manualSteps2": "「elasticsearch.serviceAccountToken」設定をkibana.ymlに追加します。", "core.deprecations.elasticsearchUsername.manualSteps3": "kibana.ymlから「elasticsearch.username」と「elasticsearch.password」を削除します。", "core.deprecations.noCorrectiveAction": "この廃止予定は自動的に解決できません。", - "core.euiAbsoluteTab.dateFormatHint": "日付として解析するには、Enterキーを押してください。", "core.euiAccordionChildrenLoading.message": "読み込み中", "core.euiAutoRefresh.autoRefreshLabel": "自動更新", "core.euiAutoRefresh.buttonLabelOff": "自動更新はオフです", @@ -5871,8 +5870,6 @@ "securitySolutionPackages.ecsDataQualityDashboard.unmanagedPatternTooltip": "{pattern}パターンと一致する{indices} {indices, plural, other {インデックス}}{indices, plural, other {は}}インデックスライフサイクル管理(ILM)によって管理されていません", "securitySolutionPackages.ecsDataQualityDashboard.warmPatternTooltip": "{pattern}パターンと一致する{indices} {indices, plural, other {インデックス}}{indices, plural, other {は}}ウォームです。ウォームインデックスは更新されませんが、まだ照会されています。", "securitySolutionPackages.entityAnalytics.paywall.upgradeButton": "{requiredLicenseOrProduct}にアップグレード", - "securitySolutionPackages.entityAnalytics.paywall.upgradeLicenseMessage": "この機能は、{requiredLicense}以上のサブスクリプションでご利用いただけます", - "securitySolutionPackages.entityAnalytics.paywall.upgradeProductMessage": "エンティティリスクスコアリング機能は、{requiredProduct}ライセンスティアで利用可能です", "securitySolutionPackages.alertSuppressionRuleDetails.upsell": "アラート非表示が構成されていますが、ライセンス不足のため適用されません", "securitySolutionPackages.beta.label": "ベータ", "securitySolutionPackages.dataTable.ariaLabel": "アラート", @@ -6782,7 +6779,6 @@ "unifiedFieldList.fieldStats.filterOutValueButtonAriaLabel": "{field}を除外:\"{value}\"", "unifiedFieldList.fieldStats.filterValueButtonAriaLabel": "{field}を除外:\"{value}\"", "unifiedFieldList.fieldStats.noFieldDataInSampleDescription": "{sampledDocumentsFormatted}サンプル{sampledDocuments, plural, other {レコード}}のフィールドデータがありません。", - "unifiedFieldList.fieldCategorizeButton.label": "パターン分析を実行", "unifiedFieldList.fieldItemButton.mappingConflictDescription": "このフィールドは、このパターンと一致するインデックス全体に対して複数の型(文字列、整数など)として定義されています。この競合フィールドを使用することはできますが、Kibana で型を認識する必要がある関数では使用できません。この問題を修正するにはデータのレンダリングが必要です。", "unifiedFieldList.fieldItemButton.mappingConflictTitle": "マッピングの矛盾", "unifiedFieldList.fieldList.noFieldsCallout.noDataLabel": "フィールドがありません。", @@ -12910,20 +12906,6 @@ "xpack.csp.findings.findingsFlyout.ruleTab.tagsTitle": "タグ", "xpack.csp.findings.findingsFlyout.ruleTabTitle": "ルール", "xpack.csp.findings.findingsFlyout.tableTabTitle": "表", - "xpack.csp.findings.findingsTable.findingsTableColumn.lastCheckedColumnLabel": "最終確認", - "xpack.csp.findings.findingsTable.findingsTableColumn.packageFixedVersionColumnLabel": "修正バージョン", - "xpack.csp.findings.findingsTable.findingsTableColumn.packageNameColumnLabel": "パッケージ", - "xpack.csp.findings.findingsTable.findingsTableColumn.packageVersionColumnLabel": "バージョン", - "xpack.csp.findings.findingsTable.findingsTableColumn.resourceIdColumnLabel": "リソースID", - "xpack.csp.findings.findingsTable.findingsTableColumn.resourceNameColumnLabel": "リソース名", - "xpack.csp.findings.findingsTable.findingsTableColumn.resourceTypeColumnLabel": "リソースタイプ", - "xpack.csp.findings.findingsTable.findingsTableColumn.resultColumnLabel": "結果", - "xpack.csp.findings.findingsTable.findingsTableColumn.ruleNameColumnLabel": "ルール名", - "xpack.csp.findings.findingsTable.findingsTableColumn.ruleNumberColumnLabel": "ルール番号", - "xpack.csp.findings.findingsTable.findingsTableColumn.ruleSectionColumnLabel": "CISセクション", - "xpack.csp.findings.findingsTable.findingsTableColumn.vulnerabilityIdColumnLabel": "脆弱性", - "xpack.csp.findings.findingsTable.findingsTableColumn.vulnerabilityScoreColumnLabel": "CVSS", - "xpack.csp.findings.findingsTable.findingsTableColumn.vulnerabilitySeverityColumnLabel": "深刻度", "xpack.csp.findings.gcpIntegration.gcpInputText.credentialFileText": "サブスクライブに使用される資格情報とキーを含むJSONファイルへのパス", "xpack.csp.findings.gcpIntegration.gcpInputText.credentialJSONText": "サブスクライブに使用される資格情報とキーを含むJSON blob", "xpack.csp.findings.gcpIntegration.gcpInputText.credentialSelectBoxTitle": "資格情報", @@ -13574,7 +13556,6 @@ "xpack.elasticAssistant.assistant.content.prompts.system.ifYouDontKnowTheAnswer": "Elasticセキュリティに関連していない質問には回答しないでください。", "xpack.elasticAssistant.assistant.content.prompts.system.superheroPersonality": "サイバーセキュリティの専門家に情報を伝えるつもりで、できるだけ詳細で関連性のある回答を入力してください。", "xpack.elasticAssistant.assistant.content.prompts.system.superheroSystemPromptName": "拡張システムプロンプト", - "xpack.elasticAssistant.assistant.content.prompts.system.useTheFollowingContextToAnswer": "次のコンテキストを使用して、質問に回答します。", "xpack.elasticAssistant.assistant.content.prompts.system.youAreAHelpfulExpertAssistant": "あなたはElasticセキュリティに関する質問に答える、親切で専門的なアシスタントです。", "xpack.elasticAssistant.assistant.content.prompts.user.finallySuggestInvestigationGuideAndFormatAsMarkdown": "説明、推奨されるアクション、箇条書きのトリアージステップを追加します。提供された MITRE ATT&CKデータを使用して、MITREからのコンテキストや推奨事項を追加し、MITREのWebサイトの関連ページにハイパーリンクを貼ります。コンテキストのユーザーとホストのリスクスコアデータを必ず含めてください。回答には、エンドポイント対応アクション、ElasticエージェントOSQueryマネージャー統合(osqueryクエリの例を付けて)、タイムライン、エンティティ分析など、Elasticセキュリティ固有の機能を指す手順を含め、関連するElasticセキュリティのドキュメントすべてにリンクしてください。", "xpack.elasticAssistant.assistant.content.prompts.user.thenSummarizeSuggestedKqlAndEqlQueries": "上記のコンテキストからイベントを評価し、Elasticセキュリティのケース用に、出力をマークダウン構文で正しく書式設定してください。", @@ -18573,7 +18554,6 @@ "xpack.fleet.fleetServerSetup.addFleetServerHostButton": "ホストの追加", "xpack.fleet.fleetServerSetup.addFleetServerHostStepTitle": "Fleetサーバーホストの追加", "xpack.fleet.fleetServerSetup.addFleetServerHostSuccessTitle": "追加されたFleetサーバーホスト", - "xpack.fleet.fleetServerSetup.calloutTitle": "エージェント診断", "xpack.fleet.fleetServerSetup.cloudDeploymentLink": "デプロイを編集", "xpack.fleet.fleetServerSetup.cloudSetupTitle": "Fleetサーバーを有効にする", "xpack.fleet.fleetServerSetup.errorAddingFleetServerHostTitle": "Fleetサーバーホストの追加エラー", @@ -33559,7 +33539,6 @@ "xpack.securitySolution.assistant.content.prompts.system.outputFormatting": "KQL、EQL、ES|QLに関連する質問に回答した場合、Elastic Securityのタイムライン内ですぐに使用できるようにする必要があります。出力は常にバックティックで正しい形式にしてください。クエリDSLで提供されるすべての回答は、セキュリティタイムラインでも使用可能でなければなりません。つまり、クエリの\"フィルター\"部分のみを含める必要があります。", "xpack.securitySolution.assistant.content.prompts.system.superheroPersonality": "サイバーセキュリティの専門家に情報を伝えるつもりで、できるだけ詳細で関連性のある回答を入力してください。", "xpack.securitySolution.assistant.content.prompts.system.superheroSystemPromptName": "拡張システムプロンプト", - "xpack.securitySolution.assistant.content.prompts.system.useTheFollowingContextToAnswer": "次のコンテキストを使用して、質問に回答します。", "xpack.securitySolution.assistant.content.prompts.system.youAreAHelpfulExpertAssistant": "あなたはElasticセキュリティに関する質問に答える、親切で専門的なアシスタントです。", "xpack.securitySolution.assistant.content.prompts.user.finallySuggestInvestigationGuideAndFormatAsMarkdown": "説明、推奨されるアクション、箇条書きのトリアージステップを追加します。提供された MITRE ATT&CKデータを使用して、MITREからのコンテキストや推奨事項を追加し、MITREのWebサイトの関連ページにハイパーリンクを貼ります。コンテキストのユーザーとホストのリスクスコアデータを必ず含めてください。回答には、エンドポイント対応アクション、ElasticエージェントOSQueryマネージャー統合(osqueryクエリの例を付けて)、タイムライン、エンティティ分析など、Elasticセキュリティ固有の機能を指す手順を含め、関連するElasticセキュリティのドキュメントすべてにリンクしてください。", "xpack.securitySolution.assistant.content.prompts.user.thenSummarizeSuggestedKqlAndEqlQueries": "上記のコンテキストからイベントを評価し、Elasticセキュリティのケース用に、出力をマークダウン構文で正しく書式設定してください。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 968e567a714bd..c70ac8ffa2b99 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -688,7 +688,6 @@ "core.deprecations.elasticsearchUsername.manualSteps2": "将“elasticsearch.serviceAccountToken”设置添加到 kibana.yml。", "core.deprecations.elasticsearchUsername.manualSteps3": "从 kibana.yml 中移除“elasticsearch.username”和“elasticsearch.password”。", "core.deprecations.noCorrectiveAction": "无法自动解决此弃用。", - "core.euiAbsoluteTab.dateFormatHint": "按 Enter 键解析为日期。", "core.euiAccordionChildrenLoading.message": "正在加载", "core.euiAutoRefresh.autoRefreshLabel": "自动刷新", "core.euiAutoRefresh.buttonLabelOff": "自动刷新已关闭", @@ -5884,7 +5883,6 @@ "securitySolutionPackages.ecsDataQualityDashboard.unmanagedPatternTooltip": "与 {pattern} 模式匹配的 {indices} 个{indices, plural, other {索引}}{indices, plural, other {}}不通过索引生命周期管理 (ILM) 进行管理", "securitySolutionPackages.ecsDataQualityDashboard.warmPatternTooltip": "{indices} 个匹配 {pattern} 模式的{indices, plural, other {索引}}{indices, plural, other {为}}温索引。不再更新但仍会查询温索引。", "securitySolutionPackages.entityAnalytics.paywall.upgradeButton": "升级到 {requiredLicenseOrProduct}", - "securitySolutionPackages.entityAnalytics.paywall.upgradeLicenseMessage": "{requiredLicense}或更高级订阅可以使用此功能", "securitySolutionPackages.markdown.insight.upsell": "升级到{requiredLicense}以利用调查指南中的洞见", "securitySolutionPackages.alertSuppressionRuleDetails.upsell": "已配置告警阻止,但由于许可不足而无法应用", "securitySolutionPackages.beta.label": "公测版", @@ -6796,7 +6794,6 @@ "unifiedFieldList.fieldStats.filterOutValueButtonAriaLabel": "筛除 {field}:“{value}”", "unifiedFieldList.fieldStats.filterValueButtonAriaLabel": "筛留 {field}:“{value}”", "unifiedFieldList.fieldStats.noFieldDataInSampleDescription": "{sampledDocumentsFormatted} 个样例{sampledDocuments, plural, other {记录}}无字段数据。", - "unifiedFieldList.fieldCategorizeButton.label": "运行模式分析", "unifiedFieldList.fieldItemButton.mappingConflictDescription": "此字段在匹配此模式的各个索引中已定义为若干类型(字符串、整数等)。您可能仍可以使用此冲突字段,但它无法用于需要 Kibana 知道其类型的函数。要解决此问题,需要重新索引您的数据。", "unifiedFieldList.fieldItemButton.mappingConflictTitle": "映射冲突", "unifiedFieldList.fieldList.noFieldsCallout.noDataLabel": "无字段。", @@ -12935,20 +12932,6 @@ "xpack.csp.findings.findingsFlyout.ruleTab.tagsTitle": "标签", "xpack.csp.findings.findingsFlyout.ruleTabTitle": "规则", "xpack.csp.findings.findingsFlyout.tableTabTitle": "表", - "xpack.csp.findings.findingsTable.findingsTableColumn.lastCheckedColumnLabel": "上次检查时间", - "xpack.csp.findings.findingsTable.findingsTableColumn.packageFixedVersionColumnLabel": "修复版本", - "xpack.csp.findings.findingsTable.findingsTableColumn.packageNameColumnLabel": "软件包", - "xpack.csp.findings.findingsTable.findingsTableColumn.packageVersionColumnLabel": "版本", - "xpack.csp.findings.findingsTable.findingsTableColumn.resourceIdColumnLabel": "资源 ID", - "xpack.csp.findings.findingsTable.findingsTableColumn.resourceNameColumnLabel": "资源名称", - "xpack.csp.findings.findingsTable.findingsTableColumn.resourceTypeColumnLabel": "资源类型", - "xpack.csp.findings.findingsTable.findingsTableColumn.resultColumnLabel": "结果", - "xpack.csp.findings.findingsTable.findingsTableColumn.ruleNameColumnLabel": "规则名称", - "xpack.csp.findings.findingsTable.findingsTableColumn.ruleNumberColumnLabel": "规则编号", - "xpack.csp.findings.findingsTable.findingsTableColumn.ruleSectionColumnLabel": "CIS 部分", - "xpack.csp.findings.findingsTable.findingsTableColumn.vulnerabilityIdColumnLabel": "漏洞", - "xpack.csp.findings.findingsTable.findingsTableColumn.vulnerabilityScoreColumnLabel": "CVSS", - "xpack.csp.findings.findingsTable.findingsTableColumn.vulnerabilitySeverityColumnLabel": "严重性", "xpack.csp.findings.gcpIntegration.gcpInputText.credentialFileText": "包含用于订阅的凭据和密钥的 JSON 文件的路径", "xpack.csp.findings.gcpIntegration.gcpInputText.credentialJSONText": "包含用于订阅的凭据和密钥的 JSON Blob", "xpack.csp.findings.gcpIntegration.gcpInputText.credentialSelectBoxTitle": "凭据", @@ -13600,7 +13583,6 @@ "xpack.elasticAssistant.assistant.content.prompts.system.ifYouDontKnowTheAnswer": "不回答与 Elastic Security 无关的问题。", "xpack.elasticAssistant.assistant.content.prompts.system.superheroPersonality": "提供可能的最详细、最相关的答案,就好像您正将此信息转发给网络安全专家一样。", "xpack.elasticAssistant.assistant.content.prompts.system.superheroSystemPromptName": "已增强系统提示", - "xpack.elasticAssistant.assistant.content.prompts.system.useTheFollowingContextToAnswer": "使用以下上下文回答问题:", "xpack.elasticAssistant.assistant.content.prompts.system.youAreAHelpfulExpertAssistant": "您是一位可帮助回答 Elastic Security 相关问题的专家助手。", "xpack.elasticAssistant.assistant.content.prompts.user.finallySuggestInvestigationGuideAndFormatAsMarkdown": "添加描述、建议操作和带项目符号的分类步骤。使用提供的 MITRE ATT&CK 数据以从 MITRE 添加更多上下文和建议,以及指向 MITRE 网站上的相关页面的超链接。确保包括上下文中的用户和主机风险分数数据。您的响应应包含指向 Elastic Security 特定功能的步骤,包括终端响应操作、Elastic 代理 OSQuery 管理器集成(带示例 osquery 查询)、时间线和实体分析,以及所有相关 Elastic Security 文档的链接。", "xpack.elasticAssistant.assistant.content.prompts.user.thenSummarizeSuggestedKqlAndEqlQueries": "评估来自上述上下文的事件,并以用于我的 Elastic Security 案例的 Markdown 语法对您的输出进行全面格式化。", @@ -18602,7 +18584,6 @@ "xpack.fleet.fleetServerSetup.addFleetServerHostButton": "添加主机", "xpack.fleet.fleetServerSetup.addFleetServerHostStepTitle": "添加您的 Fleet 服务器主机", "xpack.fleet.fleetServerSetup.addFleetServerHostSuccessTitle": "已添加 Fleet 服务器主机", - "xpack.fleet.fleetServerSetup.calloutTitle": "代理诊断", "xpack.fleet.fleetServerSetup.cloudDeploymentLink": "编辑部署", "xpack.fleet.fleetServerSetup.cloudSetupTitle": "启用 Fleet 服务器", "xpack.fleet.fleetServerSetup.errorAddingFleetServerHostTitle": "添加 Fleet 服务器主机时出错", @@ -33602,7 +33583,6 @@ "xpack.securitySolution.assistant.content.prompts.system.outputFormatting": "如果您回答与 KQL、EQL 或 ES|QL 相关的问题,它应在 Elastic Security 时间线中立即可用;请始终用反勾号对输出进行正确格式化。为查询 DSL 提供的任何答案也应在安全时间线中可用。这意味着您只应包括查询的“筛选”部分。", "xpack.securitySolution.assistant.content.prompts.system.superheroPersonality": "提供可能的最详细、最相关的答案,就好像您正将此信息转发给网络安全专家一样。", "xpack.securitySolution.assistant.content.prompts.system.superheroSystemPromptName": "已增强系统提示", - "xpack.securitySolution.assistant.content.prompts.system.useTheFollowingContextToAnswer": "使用以下上下文回答问题:", "xpack.securitySolution.assistant.content.prompts.system.youAreAHelpfulExpertAssistant": "您是一位可帮助回答 Elastic Security 相关问题的专家助手。", "xpack.securitySolution.assistant.content.prompts.user.finallySuggestInvestigationGuideAndFormatAsMarkdown": "添加描述、建议操作和带项目符号的分类步骤。使用提供的 MITRE ATT&CK 数据以从 MITRE 添加更多上下文和建议,以及指向 MITRE 网站上的相关页面的超链接。确保包括上下文中的用户和主机风险分数数据。您的响应应包含指向 Elastic Security 特定功能的步骤,包括终端响应操作、Elastic 代理 OSQuery 管理器集成(带示例 osquery 查询)、时间线和实体分析,以及所有相关 Elastic Security 文档的链接。", "xpack.securitySolution.assistant.content.prompts.user.thenSummarizeSuggestedKqlAndEqlQueries": "评估来自上述上下文的事件,并以用于我的 Elastic Security 案例的 Markdown 语法对您的输出进行全面格式化。", diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rule_status_dropdown.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rule_status_dropdown.tsx index 624e6e5f276e7..ddd836a4f0993 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rule_status_dropdown.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rule_status_dropdown.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useState, useEffect, useCallback } from 'react'; +import React, { useState, useCallback } from 'react'; import moment from 'moment'; import { i18n } from '@kbn/i18n'; import type { RuleSnooze } from '@kbn/alerting-plugin/common'; @@ -29,7 +29,6 @@ import { Rule, SnoozeSchedule, BulkOperationResponse } from '../../../../types'; import { ToastWithCircuitBreakerContent } from '../../../components/toast_with_circuit_breaker_content'; import { UntrackAlertsModal } from '../../common/components/untrack_alerts_modal'; -export type SnoozeUnit = 'm' | 'h' | 'd' | 'w' | 'M'; const SNOOZE_END_TIME_FORMAT = 'LL @ LT'; type DropdownRuleRecord = Pick< @@ -60,24 +59,16 @@ export const RuleStatusDropdown: React.FunctionComponent = ({ hideSnoozeOption = false, direction = 'column', }: ComponentOpts) => { - const [isEnabled, setIsEnabled] = useState(rule.enabled); - const [isSnoozed, setIsSnoozed] = useState(!hideSnoozeOption && isRuleSnoozed(rule)); - const { notifications: { toasts }, i18n: i18nStart, theme, } = useKibana().services; - useEffect(() => { - setIsEnabled(rule.enabled); - }, [rule.enabled]); - useEffect(() => { - if (!hideSnoozeOption) setIsSnoozed(isRuleSnoozed(rule)); - }, [rule, hideSnoozeOption]); const [isUpdating, setIsUpdating] = useState(false); const [isPopoverOpen, setIsPopoverOpen] = useState(false); const [isUntrackAlertsModalOpen, setIsUntrackAlertsModalOpen] = useState(false); + const isSnoozed = !hideSnoozeOption && isRuleSnoozed(rule); const onClickBadge = useCallback(() => setIsPopoverOpen((isOpen) => !isOpen), [setIsPopoverOpen]); const onClosePopover = useCallback(() => setIsPopoverOpen(false), [setIsPopoverOpen]); @@ -106,7 +97,6 @@ export const RuleStatusDropdown: React.FunctionComponent = ({ setIsUpdating(true); try { await enableRuleInternal(); - setIsEnabled(true); onRuleChanged(); } finally { setIsUpdating(false); @@ -118,7 +108,6 @@ export const RuleStatusDropdown: React.FunctionComponent = ({ setIsUpdating(true); try { await disableRule(untrack); - setIsEnabled(false); onRuleChanged(); } finally { setIsUpdating(false); @@ -181,11 +170,11 @@ export const RuleStatusDropdown: React.FunctionComponent = ({ [unsnoozeRule, onRuleChanged, onClosePopover] ); - const badgeColor = !isEnabled ? 'default' : isSnoozed ? 'warning' : 'primary'; - const badgeMessage = !isEnabled ? DISABLED : isSnoozed ? SNOOZED : ENABLED; + const badgeColor = !rule.enabled ? 'default' : isSnoozed ? 'warning' : 'primary'; + const badgeMessage = !rule.enabled ? DISABLED : isSnoozed ? SNOOZED : ENABLED; const remainingSnoozeTime = - isEnabled && isSnoozed ? ( + rule.enabled && isSnoozed ? ( = ({ { await ml.api.createAndRunAnomalyDetectionLookbackJob( testData.jobConfig, diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/backfill/task_runner.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/backfill/task_runner.ts index 6b555198e5eff..aa81a4713a8af 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/backfill/task_runner.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/backfill/task_runner.ts @@ -92,7 +92,7 @@ export default function createBackfillTaskRunnerTests({ getService }: FtrProvide await esTestIndexTool.setup(); }); afterEach(async () => { - objectRemover.removeAll(); + await objectRemover.removeAll(); await esTestIndexTool.destroy(); }); after(async () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/find.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/find.ts index 7abc1b134f01d..e7461476a2996 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/find.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/find.ts @@ -19,8 +19,10 @@ const findTestUtils = ( supertest: SuperTestAgent, supertestWithoutAuth: any ) => { - describe.skip(describeType, () => { - afterEach(() => objectRemover.removeAll()); + describe(describeType, () => { + afterEach(async () => { + await objectRemover.removeAll(); + }); for (const scenario of UserAtSpaceScenarios) { const { user, space } = scenario; @@ -651,12 +653,12 @@ export default function createFindTests({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const supertestWithoutAuth = getService('supertestWithoutAuth'); - // Failing: See https://github.com/elastic/kibana/issues/182263 - // Failing: See https://github.com/elastic/kibana/issues/182284 - describe.skip('find', () => { + describe('find', () => { const objectRemover = new ObjectRemover(supertest); - afterEach(() => objectRemover.removeAll()); + afterEach(async () => { + await objectRemover.removeAll(); + }); findTestUtils('public', objectRemover, supertest, supertestWithoutAuth); findTestUtils('internal', objectRemover, supertest, supertestWithoutAuth); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/find_with_post.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/find_with_post.ts index 82956536c6d1a..b407ee072a78b 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/find_with_post.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/find_with_post.ts @@ -19,14 +19,14 @@ const findTestUtils = ( supertest: SuperTestAgent, supertestWithoutAuth: any ) => { - // FLAKY: https://github.com/elastic/kibana/issues/182314 - describe.skip(describeType, () => { - afterEach(() => objectRemover.removeAll()); + describe(describeType, () => { + afterEach(async () => { + await objectRemover.removeAll(); + }); for (const scenario of UserAtSpaceScenarios) { const { user, space } = scenario; - // FLAKY: https://github.com/elastic/kibana/issues/182314 - describe.skip(scenario.id, () => { + describe(scenario.id, () => { it('should handle find alert request appropriately', async () => { const { body: createdAlert } = await supertest .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) @@ -581,7 +581,9 @@ export default function createFindTests({ getService }: FtrProviderContext) { describe('find with post', () => { const objectRemover = new ObjectRemover(supertest); - afterEach(() => objectRemover.removeAll()); + afterEach(async () => { + await objectRemover.removeAll(); + }); findTestUtils('internal', objectRemover, supertest, supertestWithoutAuth); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/telemetry/alerting_and_actions_telemetry.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/telemetry/alerting_and_actions_telemetry.ts index afe7275e808b1..000ff81d2d2dc 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/telemetry/alerting_and_actions_telemetry.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/telemetry/alerting_and_actions_telemetry.ts @@ -7,6 +7,7 @@ import expect from '@kbn/expect'; import { ESTestIndexTool } from '@kbn/alerting-api-integration-helpers'; +import { OpenAISimulator } from '@kbn/actions-simulators-plugin/server/openai_simulation'; import { Spaces, Superuser } from '../../../scenarios'; import { getUrlPrefix, @@ -25,24 +26,43 @@ export default function createAlertingAndActionsTelemetryTests({ getService }: F const retry = getService('retry'); const esTestIndexTool = new ESTestIndexTool(es, retry); const supertestWithoutAuth = getService('supertestWithoutAuth'); + const configService = getService('config'); describe('test telemetry', () => { const objectRemover = new ObjectRemover(supertest); const esQueryRuleId: { [key: string]: string } = {}; + const simulator = new OpenAISimulator({ + returnError: false, + proxy: { + config: configService.get('kbnTestServer.serverArgs'), + }, + }); + let apiUrl: string; beforeEach(async () => { await esTestIndexTool.destroy(); await esTestIndexTool.setup(); }); + before(async () => { + apiUrl = await simulator.start(); + }); + afterEach(() => objectRemover.removeAll()); after(async () => { + simulator.close(); await esTestIndexTool.destroy(); }); - async function createConnector(opts: { name: string; space: string; connectorTypeId: string }) { - const { name, space, connectorTypeId } = opts; + async function createConnector(opts: { + name: string; + space: string; + connectorTypeId: string; + secrets?: { apiKey: string }; + config?: { apiProvider: string; apiUrl: string }; + }) { + const { name, space, connectorTypeId, secrets, config } = opts; const { body: createdConnector } = await supertestWithoutAuth .post(`${getUrlPrefix(space)}/api/actions/connector`) .set('kbn-xsrf', 'foo') @@ -50,8 +70,8 @@ export default function createAlertingAndActionsTelemetryTests({ getService }: F .send({ name, connector_type_id: connectorTypeId, - config: {}, - secrets: {}, + config: config || {}, + secrets: secrets || {}, }) .expect(200); objectRemover.add(space, createdConnector.id, 'connector', 'actions'); @@ -89,7 +109,18 @@ export default function createAlertingAndActionsTelemetryTests({ getService }: F space: space.id, connectorTypeId: 'test.excluded', }); - + const genAiConnectorId = await createConnector({ + name: 'gen ai connector', + space: space.id, + connectorTypeId: '.gen-ai', + secrets: { + apiKey: 'genAiApiKey', + }, + config: { + apiProvider: 'OpenAI', + apiUrl, + }, + }); await createRule({ space: space.id, ruleOverwrites: { @@ -115,6 +146,11 @@ export default function createAlertingAndActionsTelemetryTests({ getService }: F group: 'default', params: {}, }, + { + id: genAiConnectorId, + group: 'default', + params: {}, + }, ], }, }); @@ -186,7 +222,7 @@ export default function createAlertingAndActionsTelemetryTests({ getService }: F function verifyActionsTelemetry(telemetry: any) { logger.info(`actions telemetry - ${JSON.stringify(telemetry)}`); // total number of active connectors (used by a rule) - expect(telemetry.count_active_total).to.equal(7); + expect(telemetry.count_active_total).to.equal(10); // total number of connectors broken down by connector type expect(telemetry.count_by_type['test.throw']).to.equal(3); @@ -198,6 +234,8 @@ export default function createAlertingAndActionsTelemetryTests({ getService }: F expect(telemetry.count_by_type.__index).to.equal(1); expect(telemetry.count_by_type['test.index-record']).to.equal(1); expect(telemetry.count_by_type.__webhook).to.equal(4); + expect(telemetry.count_by_type['__gen-ai']).to.equal(3); + expect(telemetry.count_gen_ai_provider_types.OpenAI).to.equal(3); // total number of active connectors broken down by connector type expect(telemetry.count_active_by_type['test.throw']).to.equal(3); @@ -284,8 +322,8 @@ export default function createAlertingAndActionsTelemetryTests({ getService }: F // attached connectors stats expect(telemetry.connectors_per_alert.min).to.equal(0); - expect(telemetry.connectors_per_alert.avg).to.equal(0.8); - expect(telemetry.connectors_per_alert.max).to.equal(3); + expect(telemetry.connectors_per_alert.avg).to.equal(1); + expect(telemetry.connectors_per_alert.max).to.equal(4); // number of spaces with rules expect(telemetry.count_rules_namespaces).to.equal(3); @@ -497,7 +535,7 @@ export default function createAlertingAndActionsTelemetryTests({ getService }: F expect(taskState).not.to.be(undefined); actionsTelemetry = JSON.parse(taskState!); expect(actionsTelemetry.runs > 0).to.be(true); - expect(actionsTelemetry.count_total).to.equal(21); + expect(actionsTelemetry.count_total).to.equal(24); }); verifyActionsTelemetry(actionsTelemetry); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/alert_delay.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/alert_delay.ts index 7062c1c65fd9c..e3f30d252495a 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/alert_delay.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/alert_delay.ts @@ -43,7 +43,7 @@ export default function createAlertDelayTests({ getService }: FtrProviderContext instance: [true, true, true, false, true], }; - const ruleId = await createRule(actionId, pattern, 20); + const ruleId = await createRule(actionId, pattern, 1); objectRemover.add(space.id, ruleId, 'rule', 'alerting'); let state = await getAlertState(start, ruleId); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/alerts_as_data/alerts_as_data_alert_delay.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/alerts_as_data/alerts_as_data_alert_delay.ts index 991ed513ee984..2bb97a60bf0c2 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/alerts_as_data/alerts_as_data_alert_delay.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/alerts_as_data/alerts_as_data_alert_delay.ts @@ -80,16 +80,17 @@ export default function createAlertsAsDataAlertDelayInstallResourcesTest({ conflicts: 'proceed', }); }); - afterEach(() => objectRemover.removeAll()); - after(async () => { - await objectRemover.removeAll(); - await esTestIndexTool.destroy(); + afterEach(async () => { + objectRemover.removeAll(); await es.deleteByQuery({ index: [alertsAsDataIndex, alwaysFiringAlertsAsDataIndex], query: { match_all: {} }, conflicts: 'proceed', }); }); + after(async () => { + await esTestIndexTool.destroy(); + }); it('should generate expected events with a alertDelay with AAD', async () => { const { body: createdAction } = await supertestWithoutAuth @@ -620,6 +621,138 @@ export default function createAlertsAsDataAlertDelayInstallResourcesTest({ // alert consecutive matches should match the active count expect(source[ALERT_CONSECUTIVE_MATCHES]).to.equal(4); }); + + it('should not recover alert if the activeCount did not reach the alertDelay threshold with AAD', async () => { + const { body: createdAction } = await supertestWithoutAuth + .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/connector`) + .set('kbn-xsrf', 'foo') + .send({ + name: 'MY action', + connector_type_id: 'test.noop', + config: {}, + secrets: {}, + }) + .expect(200); + + // pattern of when the alert should fire + const pattern = { + instance: [true, false, true], + }; + + const response = await supertestWithoutAuth + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send( + getTestRuleData({ + rule_type_id: 'test.patternFiringAad', + schedule: { interval: '1d' }, + throttle: null, + notify_when: null, + params: { + pattern, + }, + actions: [ + { + id: createdAction.id, + group: 'default', + params: {}, + frequency: { + summary: false, + throttle: null, + notify_when: RuleNotifyWhen.CHANGE, + }, + }, + ], + alert_delay: { + active: 3, + }, + }) + ); + + expect(response.status).to.eql(200); + const ruleId = response.body.id; + objectRemover.add(Spaces.space1.id, ruleId, 'rule', 'alerting'); + + // -------------------------- + // RUN 1 - 0 new alerts + // -------------------------- + let events: IValidatedEvent[] = await waitForEventLogDocs( + ruleId, + new Map([['execute', { equal: 1 }]]) + ); + let executeEvent = events[0]; + expect(get(executeEvent, ACTIVE_PATH)).to.be(0); + expect(get(executeEvent, NEW_PATH)).to.be(0); + expect(get(executeEvent, RECOVERED_PATH)).to.be(0); + expect(get(executeEvent, ACTION_PATH)).to.be(0); + expect(get(executeEvent, DELAYED_PATH)).to.be(1); + + // Query for alerts + const alertDocsRun1 = await queryForAlertDocs(); + + // Get alert state from task document + let state: any = await getTaskState(ruleId); + expect(state.alertInstances.instance.meta.activeCount).to.equal(1); + expect(state.alertInstances.instance.state.patternIndex).to.equal(0); + + // After the first run, we should have 0 alert docs for the 0 active alerts + expect(alertDocsRun1.length).to.equal(0); + + // -------------------------- + // RUN 2 - 0 new alerts + // -------------------------- + let runSoon = await supertestWithoutAuth + .post(`${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rule/${ruleId}/_run_soon`) + .set('kbn-xsrf', 'foo'); + expect(runSoon.status).to.eql(204); + + events = await waitForEventLogDocs(ruleId, new Map([['execute', { equal: 2 }]])); + executeEvent = events[1]; + expect(get(executeEvent, ACTIVE_PATH)).to.be(0); + expect(get(executeEvent, NEW_PATH)).to.be(0); + expect(get(executeEvent, RECOVERED_PATH)).to.be(0); + expect(get(executeEvent, ACTION_PATH)).to.be(0); + expect(get(executeEvent, DELAYED_PATH)).to.be(0); + + // Query for alerts + const alertDocsRun2 = await queryForAlertDocs(); + + // Get alert state from task document + state = await getTaskState(ruleId); + expect(state.alertInstances).to.eql({}); + expect(state.alertRecoveredInstances).to.eql({}); + expect(state.alertTypeState.patternIndex).to.equal(2); + + // After the second run, we should have 0 alert docs for the 0 recovered alerts + expect(alertDocsRun2.length).to.equal(0); + + // -------------------------- + // RUN 3 - 0 new alerts + // -------------------------- + runSoon = await supertestWithoutAuth + .post(`${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rule/${ruleId}/_run_soon`) + .set('kbn-xsrf', 'foo'); + expect(runSoon.status).to.eql(204); + + events = await waitForEventLogDocs(ruleId, new Map([['execute', { equal: 3 }]])); + executeEvent = events[2]; + expect(get(executeEvent, ACTIVE_PATH)).to.be(0); + expect(get(executeEvent, NEW_PATH)).to.be(0); + expect(get(executeEvent, RECOVERED_PATH)).to.be(0); + expect(get(executeEvent, ACTION_PATH)).to.be(0); + expect(get(executeEvent, DELAYED_PATH)).to.be(1); + + // Query for alerts + const alertDocsRun3 = await queryForAlertDocs(); + + // Get alert state from task document + state = await getTaskState(ruleId); + expect(state.alertInstances.instance.meta.activeCount).to.equal(1); + expect(state.alertInstances.instance.state.patternIndex).to.equal(2); + + // After the third run, we should have 0 alert docs for the 0 active alerts + expect(alertDocsRun3.length).to.equal(0); + }); }); function testExpectRuleData( diff --git a/x-pack/test/api_integration/apis/management/rollup/rollup.js b/x-pack/test/api_integration/apis/management/rollup/rollup.js index 699592fd99920..a44da818a94e4 100644 --- a/x-pack/test/api_integration/apis/management/rollup/rollup.js +++ b/x-pack/test/api_integration/apis/management/rollup/rollup.js @@ -24,7 +24,8 @@ export default function ({ getService }) { cleanUp, } = registerHelpers(getService); - describe('jobs', () => { + // Failing: See https://github.com/elastic/kibana/issues/184073 + describe.skip('jobs', () => { after(() => cleanUp()); describe('indices', () => { @@ -92,7 +93,8 @@ export default function ({ getService }) { }); }); - describe('create', () => { + // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/183928 + describe.skip('create', () => { let indexName; beforeEach(async () => { diff --git a/x-pack/test/api_integration/apis/metrics_ui/services.ts b/x-pack/test/api_integration/apis/metrics_ui/services.ts index 959e6f1109e74..d8bc483b6ce6a 100644 --- a/x-pack/test/api_integration/apis/metrics_ui/services.ts +++ b/x-pack/test/api_integration/apis/metrics_ui/services.ts @@ -20,7 +20,8 @@ export default function ({ getService }: FtrProviderContext) { const apmSynthtraceKibanaClient = getService('apmSynthtraceKibanaClient'); const esClient = getService('es'); - describe('GET /infra/services', () => { + // Failing: See https://github.com/elastic/kibana/issues/176967 + describe.skip('GET /infra/services', () => { let synthtraceApmClient: ApmSynthtraceEsClient; const from = new Date(Date.now() - 1000 * 60 * 2).toISOString(); const to = new Date().toISOString(); diff --git a/x-pack/test/api_integration/apis/security/api_keys.ts b/x-pack/test/api_integration/apis/security/api_keys.ts index 3a9edb14a3d15..f92d427f0160d 100644 --- a/x-pack/test/api_integration/apis/security/api_keys.ts +++ b/x-pack/test/api_integration/apis/security/api_keys.ts @@ -12,6 +12,8 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); + const config = getService('config'); + const basic = config.get('esTestCluster.license') === 'basic'; describe('API Keys', () => { describe('GET /internal/security/api_key/_enabled', () => { @@ -65,6 +67,81 @@ export default function ({ getService }: FtrProviderContext) { expect(name).to.eql('test_api_key_with_metadata'); }); }); + + it(`${basic ? 'basic' : 'trial'} license should ${ + basic ? 'not allow' : 'allow' + } a cross cluster API Key to be created`, async () => { + const result = await supertest + .post('/internal/security/api_key') + .set('kbn-xsrf', 'xxx') + .send({ + type: 'cross_cluster', + name: 'test_cc_api_key', + metadata: {}, + access: { + search: [ + { + names: ['logs*'], + query: { bool: { must_not: { term: { field2: 'value2' } } } }, + field_security: { grant: ['field2'] }, + allow_restricted_indices: true, + }, + ], + }, + }); + expect(result.status).to.be(basic ? 403 : 200); + if (!basic) { + expect(result.body.name).to.be('test_cc_api_key'); + } + }); + + if (!basic) { + it(`Elasticsearch should reject an invalid cross cluster API Key configuration`, async () => { + await supertest + .post('/internal/security/api_key') + .set('kbn-xsrf', 'xxx') + .send({ + type: 'cross_cluster', + name: 'test_cc_api_key_failure', + metadata: {}, + access: { + search: [ + { + names: ['logs*'], + query: { bool: { must_not: { term: { field2: 'value2' } } } }, + }, + ], + // replication section is not allowed if earch contains query or field_security + replication: { + names: ['logs*'], + }, + }, + }) + .expect(400); + + await supertest + .post('/internal/security/api_key') + .set('kbn-xsrf', 'xxx') + .send({ + type: 'cross_cluster', + name: 'test_cc_api_key_failure', + metadata: {}, + access: { + search: [ + { + names: ['logs*'], + field_security: { grant: ['field2'] }, + }, + ], + // replication section is not allowed if earch contains query or field_security + replication: { + names: ['logs*'], + }, + }, + }) + .expect(400); + }); + } }); describe('PUT /internal/security/api_key', () => { @@ -102,7 +179,176 @@ export default function ({ getService }: FtrProviderContext) { const { updated } = response.body; expect(updated).to.eql(true); }); + + const getResult = await supertest + .get('/internal/security/api_key') + .set('kbn-xsrf', 'xxx') + .send(); + + expect(getResult.body.apiKeys).to.not.be(undefined); + const updatedKey = getResult.body.apiKeys.find( + (apiKey: { id: string }) => apiKey.id === id + ); + expect(updatedKey).to.not.be(undefined); + expect(updatedKey.metadata).to.eql({ foo: 'bar' }); + expect(updatedKey.role_descriptors).to.eql({ + role_1: { + cluster: ['monitor'], + indices: [], + applications: [], + run_as: [], + metadata: {}, + transient_metadata: { + enabled: true, + }, + }, + }); }); + + it(`${basic ? 'basic' : 'trial'} license should ${ + basic ? 'not allow' : 'allow' + } a cross cluster API Key to be updated`, async () => { + let id = '123456'; + + const createResult = await supertest + .post('/internal/security/api_key') + .set('kbn-xsrf', 'xxx') + .send({ + type: 'cross_cluster', + name: 'test_cc_api_key', + metadata: {}, + access: { + search: [ + { + names: ['logs*'], + query: { bool: { must_not: { term: { field2: 'value2' } } } }, + field_security: { grant: ['field2'] }, + allow_restricted_indices: true, + }, + ], + }, + }); + expect(createResult.status).to.be(basic ? 403 : 200); + if (!basic) { + id = createResult.body.id; + } + + const updateResult = await supertest + .put('/internal/security/api_key') + .set('kbn-xsrf', 'xxx') + .send({ + type: 'cross_cluster', + id, + metadata: { + foo: 'bar', + }, + access: { + search: [ + { + names: ['somethingelse*'], + query: { bool: { must_not: { term: { field2: 'value3' } } } }, + field_security: { grant: ['field3'] }, + allow_restricted_indices: false, + }, + ], + }, + }); + expect(updateResult.status).to.be(basic ? 403 : 200); + if (!basic) { + expect(updateResult.body.updated).to.be(true); + + const getResult = await supertest + .get('/internal/security/api_key') + .set('kbn-xsrf', 'xxx') + .send(); + + expect(getResult.body.apiKeys).to.not.be(undefined); + const updatedKey = getResult.body.apiKeys.find( + (apiKey: { id: string }) => apiKey.id === id + ); + expect(updatedKey).to.not.be(undefined); + expect(updatedKey.metadata).to.eql({ foo: 'bar' }); + expect(updatedKey.role_descriptors?.cross_cluster?.indices).to.eql([ + { + names: ['somethingelse*'], + privileges: ['read', 'read_cross_cluster', 'view_index_metadata'], + field_security: { grant: ['field3'] }, + query: '{"bool":{"must_not":{"term":{"field2":"value3"}}}}', + allow_restricted_indices: false, + }, + ]); + } + }); + + if (!basic) { + it(`Elasticsearch should reject an invalid cross cluster API Key configuration`, async () => { + const createResult = await supertest + .post('/internal/security/api_key') + .set('kbn-xsrf', 'xxx') + .send({ + type: 'cross_cluster', + name: 'test_cc_api_key', + metadata: {}, + access: { + search: [ + { + names: ['logs*'], + }, + ], + }, + }); + expect(createResult.status).to.be(200); + const id = createResult.body.id; + + await supertest + .put('/internal/security/api_key') + .set('kbn-xsrf', 'xxx') + .send({ + type: 'cross_cluster', + id, + metadata: { + foo: 'bar', + }, + access: { + search: [ + { + names: ['logs*'], + query: { bool: { must_not: { term: { field2: 'value2' } } } }, + }, + ], + // replication section is not allowed if earch contains query or field_security + replication: { + names: ['logs*'], + }, + }, + }) + .expect(400); + + await supertest + .put('/internal/security/api_key') + .set('kbn-xsrf', 'xxx') + .send({ + type: 'cross_cluster', + id, + metadata: { + foo: 'bar', + }, + access: { + search: [ + { + names: ['logs*'], + field_security: { grant: ['field2'] }, + }, + ], + // replication section is not allowed if earch contains query or field_security + replication: { + names: ['logs*'], + }, + }, + }) + .expect(400); + }); + } }); describe('with kibana privileges', () => { diff --git a/x-pack/test/api_integration/apis/slos/fetch_historical_summary.ts b/x-pack/test/api_integration/apis/slos/fetch_historical_summary.ts index 94cccf1e14938..b8ca6a03b3d8e 100644 --- a/x-pack/test/api_integration/apis/slos/fetch_historical_summary.ts +++ b/x-pack/test/api_integration/apis/slos/fetch_historical_summary.ts @@ -20,8 +20,8 @@ export default function ({ getService }: FtrProviderContext) { const sloApi = getService('slo'); const SLO_ID = 'slo-fake-1'; - // Failing: See https://github.com/elastic/kibana/issues/183750 - describe.skip('fetch historical summary', () => { + + describe('fetch historical summary', () => { before(async () => { const now = moment().startOf('minute'); const curr = now.clone().subtract(30, 'days'); @@ -81,7 +81,8 @@ export default function ({ getService }: FtrProviderContext) { }); expect(response[0].sloId).to.eql(SLO_ID); expect(response[0].instanceId).to.eql(ALL_VALUE); - expect(response[0].data).to.have.length(168); // 7 days * 24 hours/day * 1 bucket/hour + const numberOfBuckets = response[0].data.length; + expect(numberOfBuckets).to.be.within(168, 170); // 7 days * 24 hours/day * 1 bucket/hour + 2 extra bucket due to histogram agg rounding const last = response[0].data.pop(); expect(last?.errorBudget).to.eql({ consumed: 1, @@ -116,7 +117,8 @@ export default function ({ getService }: FtrProviderContext) { }); expect(response[0].sloId).to.eql(SLO_ID); expect(response[0].instanceId).to.eql(ALL_VALUE); - expect(response[0].data).to.have.length(168); // 7 days * 24 hours/day * 1 bucket/hour + const numberOfBuckets = response[0].data.length; + expect(numberOfBuckets).to.be.within(168, 170); // 7 days * 24 hours/day * 1 bucket/hour + 2 extra bucket due to histogram agg rounding const last = response[0].data.pop(); expect(last?.errorBudget).to.eql({ consumed: 0, diff --git a/x-pack/test/apm_api_integration/tests/index.ts b/x-pack/test/apm_api_integration/tests/index.ts index c8eec324f4bd7..ae5b30b175825 100644 --- a/x-pack/test/apm_api_integration/tests/index.ts +++ b/x-pack/test/apm_api_integration/tests/index.ts @@ -29,7 +29,8 @@ export default function apmApiIntegrationTests({ getService, loadTestFile }: Ftr // DO NOT SKIP // Skipping here will skip the entire apm api test suite // Instead skip (flaky) tests individually - describe('APM API tests', function () { + // Failing: See https://github.com/elastic/kibana/issues/176948 + describe.skip('APM API tests', function () { const filePattern = getGlobPattern(); const tests = globby.sync(filePattern, { cwd }); diff --git a/x-pack/test/cloud_security_posture_functional/pages/findings_grouping.ts b/x-pack/test/cloud_security_posture_functional/pages/findings_grouping.ts index 09f200913773e..a7f36230bb1a5 100644 --- a/x-pack/test/cloud_security_posture_functional/pages/findings_grouping.ts +++ b/x-pack/test/cloud_security_posture_functional/pages/findings_grouping.ts @@ -403,7 +403,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await groupSelector.setValue('Resource'); // Filter bar uses the field's customLabel in the DataView - await filterBar.addFilter({ field: 'Rule Name', operation: 'is', value: ruleName1 }); + await filterBar.addFilter({ field: 'rule.name', operation: 'is', value: ruleName1 }); expect(await filterBar.hasFilter('rule.name', ruleName1)).to.be(true); const grouping = await findings.findingsGrouping(); diff --git a/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy_root_integrations.ts b/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy_root_integrations.ts new file mode 100644 index 0000000000000..1de66d530d184 --- /dev/null +++ b/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy_root_integrations.ts @@ -0,0 +1,133 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { v4 as uuidv4 } from 'uuid'; +import { FtrProviderContext } from '../../../api_integration/ftr_provider_context'; +import { setupFleetAndAgents } from '../agents/services'; +import { skipIfNoDockerRegistry } from '../../helpers'; + +export default function (providerContext: FtrProviderContext) { + const { getService } = providerContext; + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + + describe('agent policy with root integrations', () => { + skipIfNoDockerRegistry(providerContext); + before(async () => { + await esArchiver.load('x-pack/test/functional/es_archives/fleet/empty_fleet_server'); + }); + setupFleetAndAgents(providerContext); + + after(async () => { + await esArchiver.unload('x-pack/test/functional/es_archives/fleet/empty_fleet_server'); + }); + + describe('root integrations', () => { + before(async () => { + await supertest + .post(`/api/fleet/epm/packages/auditd_manager/1.16.3`) + .set('kbn-xsrf', 'xxxx') + .send({ force: true }) + .expect(200); + }); + after(async () => { + await supertest + .delete(`/api/fleet/epm/packages/auditd_manager/1.16.3`) + .set('kbn-xsrf', 'xxxx') + .send({ force: true }) + .expect(200); + }); + + it('should have root integrations in agent policy response', async () => { + // Create agent policy + const { + body: { + item: { id: agentPolicyId }, + }, + } = await supertest + .post(`/api/fleet/agent_policies`) + .set('kbn-xsrf', 'xxxx') + .send({ + name: `Test policy ${uuidv4()}`, + namespace: 'default', + monitoring_enabled: [], + }) + .expect(200); + + await supertest + .post(`/api/fleet/package_policies`) + .set('kbn-xsrf', 'xxxx') + .send({ + name: `auditd-${uuidv4()}`, + description: '', + namespace: 'default', + policy_id: agentPolicyId, + package: { + name: 'auditd_manager', + version: '1.16.3', + }, + inputs: [ + { + type: 'audit/auditd', + policy_template: 'auditd', + enabled: true, + streams: [ + { + enabled: true, + data_stream: { type: 'logs', dataset: 'auditd_manager.auditd' }, + vars: { + socket_type: { value: '', type: 'select' }, + immutable: { value: false, type: 'bool' }, + resolve_ids: { value: true, type: 'bool' }, + failure_mode: { value: 'silent', type: 'text' }, + audit_rules: { type: 'textarea' }, + audit_rule_files: { type: 'text' }, + preserve_original_event: { value: false, type: 'bool' }, + backlog_limit: { value: 8192, type: 'text' }, + rate_limit: { value: 0, type: 'text' }, + include_warnings: { value: false, type: 'bool' }, + backpressure_strategy: { value: 'auto', type: 'text' }, + tags: { value: ['auditd_manager-auditd'], type: 'text' }, + processors: { type: 'yaml' }, + }, + }, + ], + }, + ], + }) + .expect(200); + + // Fetch the agent policy + const { + body: { item: agentPolicy }, + } = await supertest + .get(`/api/fleet/agent_policies/${agentPolicyId}`) + .set('kbn-xsrf', 'xxxx'); + + // Check that the root integrations are correct + expect( + Object.values(agentPolicy.package_policies.map((policy: any) => policy.package)) + ).to.eql([ + { + name: 'auditd_manager', + title: 'Auditd Manager', + requires_root: true, + version: '1.16.3', + }, + ]); + + // Cleanup agent and package policy + await supertest + .post(`/api/fleet/agent_policies/delete`) + .send({ agentPolicyId }) + .set('kbn-xsrf', 'xxxx') + .expect(200); + }); + }); + }); +} diff --git a/x-pack/test/fleet_api_integration/apis/agent_policy/index.js b/x-pack/test/fleet_api_integration/apis/agent_policy/index.js index 559367c1a6b81..66abbf8d6a5b3 100644 --- a/x-pack/test/fleet_api_integration/apis/agent_policy/index.js +++ b/x-pack/test/fleet_api_integration/apis/agent_policy/index.js @@ -11,5 +11,6 @@ export default function loadTests({ loadTestFile }) { loadTestFile(require.resolve('./agent_policy')); loadTestFile(require.resolve('./agent_policy_datastream_permissions')); loadTestFile(require.resolve('./privileges')); + loadTestFile(require.resolve('./agent_policy_root_integrations')); }); } diff --git a/x-pack/test/fleet_api_integration/apis/agents/request_diagnostics.ts b/x-pack/test/fleet_api_integration/apis/agents/request_diagnostics.ts index 70b1b2c20b1d1..45cca59da5e8e 100644 --- a/x-pack/test/fleet_api_integration/apis/agents/request_diagnostics.ts +++ b/x-pack/test/fleet_api_integration/apis/agents/request_diagnostics.ts @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import moment from 'moment'; import { FtrProviderContext } from '../../../api_integration/ftr_provider_context'; import { setupFleetAndAgents } from './services'; @@ -39,6 +40,10 @@ export default function (providerContext: FtrProviderContext) { const actionStatus = body.items[0]; expect(actionStatus.nbAgentsActionCreated).to.eql(agentCount); + expect( + moment(actionStatus.expiration).diff(moment(actionStatus.creationTime), 'minutes') > 170 && + moment(actionStatus.expiration).diff(moment(actionStatus.creationTime), 'minutes') < 190 + ).to.eql(true); } it('should respond 403 if user lacks fleet read permissions', async () => { diff --git a/x-pack/test/fleet_api_integration/apis/agents/uploads.ts b/x-pack/test/fleet_api_integration/apis/agents/uploads.ts index 174d511674ef6..8ea34cc8c17de 100644 --- a/x-pack/test/fleet_api_integration/apis/agents/uploads.ts +++ b/x-pack/test/fleet_api_integration/apis/agents/uploads.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - +import Moment from 'moment'; import expect from '@kbn/expect'; import { AGENT_ACTIONS_INDEX, AGENT_ACTIONS_RESULTS_INDEX } from '@kbn/fleet-plugin/common'; import { @@ -24,86 +24,143 @@ export default function (providerContext: FtrProviderContext) { const ES_INDEX_OPTIONS = { headers: { 'X-elastic-product-origin': 'fleet' } }; const cleanupFiles = async () => { - await esClient.deleteByQuery({ - index: `${FILE_STORAGE_DATA_AGENT_INDEX},${FILE_STORAGE_METADATA_AGENT_INDEX}`, - refresh: true, - ignore_unavailable: true, - query: { - bool: { - filter: [ - { - ids: { - values: ['file1', 'file1.0'], - }, - }, - ], + await esClient.deleteByQuery( + { + index: `${AGENT_ACTIONS_INDEX},${AGENT_ACTIONS_RESULTS_INDEX}`, + refresh: true, + ignore_unavailable: true, + query: { + prefix: { + action_id: 'fleet_uploads_test', + }, }, }, - }); - }; + ES_INDEX_OPTIONS + ); - describe('fleet_uploads', () => { - skipIfNoDockerRegistry(providerContext); - setupFleetAndAgents(providerContext); + await esClient.deleteByQuery( + { + index: `${FILE_STORAGE_DATA_AGENT_INDEX},${FILE_STORAGE_METADATA_AGENT_INDEX}`, + refresh: true, + ignore_unavailable: true, + query: { + match_all: {}, + }, + }, + ES_INDEX_OPTIONS + ); + }; - before(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/fleet/empty_fleet_server'); - await getService('supertest').post(`/api/fleet/setup`).set('kbn-xsrf', 'xxx').send(); - await cleanupFiles(); + const createUploadBundle = async ( + fileName: string, + opts: { + agentId: string; + expired?: boolean; + inProgress?: boolean; + error?: string; + timestamp: string; + } = { + agentId: 'agent1', + expired: false, + inProgress: false, + timestamp: Moment(Moment.now()).toISOString(), + } + ) => { + const expiration = opts.expired + ? Moment(opts.timestamp).subtract(6, 'hour') + : Moment(opts.timestamp).add(6, 'hour'); - await esClient.create({ + await esClient.index( + { index: AGENT_ACTIONS_INDEX, - id: new Date().toISOString(), refresh: true, + op_type: 'create', body: { type: 'REQUEST_DIAGNOSTICS', - action_id: 'action1', - agents: ['agent1'], - '@timestamp': '2022-10-07T11:00:00.000Z', + action_id: `fleet_uploads_test-${fileName}-action`, + agents: [opts.agentId], + '@timestamp': opts.timestamp, + expiration, }, - }); + }, + ES_INDEX_OPTIONS + ); - await esClient.create( - { - index: AGENT_ACTIONS_RESULTS_INDEX, - id: new Date().toISOString(), - refresh: true, - body: { - action_id: 'action1', - agent_id: 'agent1', - '@timestamp': '2022-10-07T12:00:00.000Z', - data: { - upload_id: 'file1', - }, + await esClient.index( + { + index: AGENT_ACTIONS_RESULTS_INDEX, + refresh: true, + op_type: 'create', + body: { + action_id: `fleet_uploads_test-${fileName}-action`, + agent_id: opts.agentId, + '@timestamp': opts.timestamp, + data: { + upload_id: fileName, }, + error: opts.error, }, - ES_INDEX_OPTIONS - ); + }, + ES_INDEX_OPTIONS + ); - await esClient.index({ + if (opts.error || opts.inProgress) { + return; + } + + await esClient.index( + { index: FILE_STORAGE_METADATA_AGENT_INDEX, - id: 'file1', + id: fileName, refresh: true, op_type: 'create', body: { - '@timestamp': new Date().toISOString(), - upload_id: 'file1', - action_id: 'action1', - agent_id: 'agent1', + '@timestamp': opts.timestamp, + upload_id: fileName, + action_id: `fleet_uploads_test-${fileName}-action`, + agent_id: opts.agentId, file: { ChunkSize: 4194304, extension: 'zip', hash: {}, mime_type: 'application/zip', mode: '0644', - name: 'elastic-agent-diagnostics-2022-10-07T12-00-00Z-00.zip', - path: '/agent/elastic-agent-diagnostics-2022-10-07T12-00-00Z-00.zip', + name: `elastic-agent-diagnostics-file-name.zip`, + path: `/agent/elastic-agent-diagnostics-file-name.zip`, size: 24917, Status: 'READY', type: 'file', }, }, - }); + }, + ES_INDEX_OPTIONS + ); + + await esClient.index( + { + index: FILE_STORAGE_DATA_AGENT_INDEX, + id: `${fileName}.0`, + op_type: 'create', + refresh: true, + body: { + '@timestamp': opts.timestamp, + last: true, + bid: fileName, + data: 'test', + }, + }, + ES_INDEX_OPTIONS + ); + }; + + describe('fleet_uploads', () => { + skipIfNoDockerRegistry(providerContext); + setupFleetAndAgents(providerContext); + + before(async () => { + await esArchiver.unload('x-pack/test/functional/es_archives/fleet/empty_fleet_server'); + await getService('supertest').post(`/api/fleet/setup`).set('kbn-xsrf', 'xxx').send(); + await cleanupFiles(); }); after(async () => { await Promise.all([ @@ -113,89 +170,136 @@ export default function (providerContext: FtrProviderContext) { }); it('should get agent uploads', async () => { - const { body } = await supertest - .get(`/api/fleet/agents/agent1/uploads`) + const fileName = 'file1'; + const agentId = 'agent1'; + const timestamp = Moment().toISOString(); + await createUploadBundle(fileName, { agentId, timestamp }); + const { + body: { items }, + } = await supertest + .get(`/api/fleet/agents/${agentId}/uploads`) .set('kbn-xsrf', 'xxx') .expect(200); - expect(body.items[0]).to.eql({ - actionId: 'action1', - createTime: '2022-10-07T11:00:00.000Z', - filePath: - '/api/fleet/agents/files/file1/elastic-agent-diagnostics-2022-10-07T12-00-00Z-00.zip', - id: 'file1', - name: 'elastic-agent-diagnostics-2022-10-07T12-00-00Z-00.zip', + const { id, filePath, ...rest } = items[0]; + expect(filePath).to.be.a('string'); + expect(rest).to.eql({ + actionId: `fleet_uploads_test-${fileName}-action`, + createTime: timestamp, + name: `elastic-agent-diagnostics-file-name.zip`, status: 'READY', }); }); it('should get agent uploaded file', async () => { - await esClient.index({ - index: FILE_STORAGE_DATA_AGENT_INDEX, - id: 'file1.0', - op_type: 'create', - refresh: true, - body: { - '@timestamp': new Date().toISOString(), - last: true, - bid: 'file1', - data: 'test', - }, - }); - + const fileName = 'file2'; + const agentId = 'agent2'; + const timestamp = Moment().toISOString(); + await createUploadBundle(fileName, { agentId, timestamp }); const { header } = await supertest - .get(`/api/fleet/agents/files/file1/elastic-agent-diagnostics-2022-10-07T12-00-00Z-00.zip`) + .get(`/api/fleet/agents/files/${fileName}/elastic-agent-diagnostics-somefilename.zip`) .set('kbn-xsrf', 'xxx') .expect(200); expect(header['content-type']).to.eql('application/octet-stream'); expect(header['content-disposition']).to.eql( - 'attachment; filename="elastic-agent-diagnostics-2022-10-07T12-00-00Z-00.zip"' + `attachment; filename="elastic-agent-diagnostics-somefilename.zip"` ); }); it('should return failed status with error message', async () => { - await esClient.create({ - index: AGENT_ACTIONS_INDEX, - id: new Date().toISOString(), - refresh: true, - body: { - type: 'REQUEST_DIAGNOSTICS', - action_id: 'action2', - agents: ['agent2'], - '@timestamp': '2022-10-07T11:00:00.000Z', - }, + const fileName = 'failed-file'; + const agentId = 'agent3'; + const timestamp = Moment().toISOString(); + await createUploadBundle(fileName, { agentId, error: 'rate limit exceeded', timestamp }); + const { body } = await supertest + .get(`/api/fleet/agents/${agentId}/uploads`) + .set('kbn-xsrf', 'xxx') + .expect(200); + + const { name, ...rest } = body.items[0]; + expect(name).to.be.a('string'); + expect(rest).to.eql({ + actionId: `fleet_uploads_test-${fileName}-action`, + createTime: timestamp, + filePath: '', + id: `fleet_uploads_test-${fileName}-action`, + status: 'FAILED', + error: 'rate limit exceeded', + }); + }); + + it('should return expired status', async () => { + const fileName = 'expired-failed'; + const agentId = 'agent4'; + const timestamp = Moment().toISOString(); + await createUploadBundle(fileName, { + agentId, + expired: true, + error: 'rate limit exceeded', + timestamp, }); - await esClient.create( - { - index: AGENT_ACTIONS_RESULTS_INDEX, - id: new Date().toISOString(), - refresh: true, - body: { - action_id: 'action2', - agent_id: 'agent2', - '@timestamp': '2022-10-07T12:00:00.000Z', - data: {}, - error: 'rate limit exceeded', - }, - }, - ES_INDEX_OPTIONS - ); const { body } = await supertest - .get(`/api/fleet/agents/agent2/uploads`) + .get(`/api/fleet/agents/${agentId}/uploads`) .set('kbn-xsrf', 'xxx') .expect(200); - expect(body.items[0]).to.eql({ - actionId: 'action2', - createTime: '2022-10-07T11:00:00.000Z', + const { name, ...rest } = body.items[0]; + expect(name).to.be.a('string'); + expect(rest).to.eql({ + actionId: `fleet_uploads_test-${fileName}-action`, + createTime: timestamp, filePath: '', - id: 'action2', - name: 'elastic-agent-diagnostics-2022-10-07T11-00-00Z-00.zip', - status: 'FAILED', + id: `fleet_uploads_test-${fileName}-action`, + status: 'EXPIRED', error: 'rate limit exceeded', }); }); + + it('should return in progress status', async () => { + const fileName = 'in-progress-file'; + const agentId = 'agent6'; + const timestamp = Moment().toISOString(); + await createUploadBundle(fileName, { agentId, inProgress: true, timestamp }); + const { + body: { items }, + } = await supertest + .get(`/api/fleet/agents/${agentId}/uploads`) + .set('kbn-xsrf', 'xxx') + .expect(200); + + const { id, name, ...rest } = items[0]; + expect(id).to.be.a('string'); + expect(name).to.be.a('string'); + expect(rest).to.eql({ + actionId: `fleet_uploads_test-${fileName}-action`, + createTime: timestamp, + filePath: '', + status: 'IN_PROGRESS', + }); + }); + + it('should delete agent uploaded file', async () => { + const fileName = 'to-delete-file'; + const agentId = 'agent7'; + const timestamp = Moment().toISOString(); + await createUploadBundle(fileName, { agentId, timestamp }); + + const { body } = await supertest + .delete(`/api/fleet/agents/files/${fileName}`) + .set('kbn-xsrf', 'xxx') + .expect(200); + + expect(body.deleted).to.eql(true); + }); + + it('should return error if file is not found for deletion', async () => { + const fileName = 'unknown-file'; + await supertest + .delete(`/api/fleet/agents/files/${fileName}`) + .set('kbn-xsrf', 'xxx') + .expect(400); + }); }); } diff --git a/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/auditd_manager/auditd_manager-1.16.3.zip b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/auditd_manager/auditd_manager-1.16.3.zip new file mode 100644 index 0000000000000..5b9c055710eff Binary files /dev/null and b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/auditd_manager/auditd_manager-1.16.3.zip differ diff --git a/x-pack/test/fleet_api_integration/apis/fleet_telemetry.ts b/x-pack/test/fleet_api_integration/apis/fleet_telemetry.ts index 831659929d86d..03ae82d06f6b7 100644 --- a/x-pack/test/fleet_api_integration/apis/fleet_telemetry.ts +++ b/x-pack/test/fleet_api_integration/apis/fleet_telemetry.ts @@ -191,6 +191,8 @@ export default function (providerContext: FtrProviderContext) { unhealthy: 1, offline: 0, updating: 0, + unenrolled: 0, + inactive: 0, num_host_urls: 2, }); }); diff --git a/x-pack/test/fleet_api_integration/apis/settings/enrollment.ts b/x-pack/test/fleet_api_integration/apis/settings/enrollment.ts index 1bb0ca927f9a2..9c1cf8ea59c51 100644 --- a/x-pack/test/fleet_api_integration/apis/settings/enrollment.ts +++ b/x-pack/test/fleet_api_integration/apis/settings/enrollment.ts @@ -42,6 +42,12 @@ export default function (providerContext: FtrProviderContext) { describe('should respond with correct enrollment settings', async function () { before(async () => { await esArchiver.load('x-pack/test/functional/es_archives/fleet/fleet_server'); + // package verification error without force + await supertest + .post(`/api/fleet/epm/packages/fleet_server`) + .set('kbn-xsrf', 'xxxx') + .send({ force: true }) + .expect(200); }); after(async () => { await esArchiver.unload('x-pack/test/functional/es_archives/fleet/fleet_server'); diff --git a/x-pack/test/functional/apps/aiops/log_pattern_analysis_in_discover.ts b/x-pack/test/functional/apps/aiops/log_pattern_analysis_in_discover.ts index 197b5b5338a17..01d2452121cb8 100644 --- a/x-pack/test/functional/apps/aiops/log_pattern_analysis_in_discover.ts +++ b/x-pack/test/functional/apps/aiops/log_pattern_analysis_in_discover.ts @@ -14,7 +14,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const retry = getService('retry'); const ml = getService('ml'); const PageObjects = getPageObjects(['common', 'timePicker', 'discover']); - const selectedField = '@message'; const totalDocCount = 14005; async function retrySwitchTab(tabIndex: number, seconds: number) { @@ -55,15 +54,14 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await PageObjects.discover.selectIndexPattern('logstash-*'); await aiops.logPatternAnalysisPage.assertDiscoverDocCount(totalDocCount); - await aiops.logPatternAnalysisPage.clickDiscoverField(selectedField); - await aiops.logPatternAnalysisPage.clickDiscoverMenuAnalyzeButton(selectedField); + await aiops.logPatternAnalysisPage.clickPatternsTab(); + await aiops.logPatternAnalysisPage.assertLogPatternAnalysisTabContentsExists(); - await aiops.logPatternAnalysisPage.assertLogPatternAnalysisFlyoutExists(); - await aiops.logPatternAnalysisPage.assertLogPatternAnalysisFlyoutTitle(selectedField); - - await aiops.logPatternAnalysisPage.setRandomSamplingOption('aiopsRandomSamplerOptionOff'); + await aiops.logPatternAnalysisPage.setRandomSamplingOptionDiscover( + 'aiopsRandomSamplerOptionOff' + ); - await aiops.logPatternAnalysisPage.assertTotalCategoriesFound(3); + await aiops.logPatternAnalysisPage.assertTotalCategoriesFoundDiscover(3); await aiops.logPatternAnalysisPage.assertCategoryTableRows(3); // get category count from the first row @@ -87,15 +85,14 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { ); await aiops.logPatternAnalysisPage.assertDiscoverDocCount(totalDocCount); - await aiops.logPatternAnalysisPage.clickDiscoverField(selectedField); - await aiops.logPatternAnalysisPage.clickDiscoverMenuAnalyzeButton(selectedField); + await aiops.logPatternAnalysisPage.clickPatternsTab(); + await aiops.logPatternAnalysisPage.assertLogPatternAnalysisTabContentsExists(); - await aiops.logPatternAnalysisPage.assertLogPatternAnalysisFlyoutExists(); - await aiops.logPatternAnalysisPage.assertLogPatternAnalysisFlyoutTitle(selectedField); - - await aiops.logPatternAnalysisPage.setRandomSamplingOption('aiopsRandomSamplerOptionOff'); + await aiops.logPatternAnalysisPage.setRandomSamplingOptionDiscover( + 'aiopsRandomSamplerOptionOff' + ); - await aiops.logPatternAnalysisPage.assertTotalCategoriesFound(3); + await aiops.logPatternAnalysisPage.assertTotalCategoriesFoundDiscover(3); await aiops.logPatternAnalysisPage.assertCategoryTableRows(3); // get category count from the first row diff --git a/x-pack/test/functional/apps/dashboard/group3/reporting/screenshots.ts b/x-pack/test/functional/apps/dashboard/group3/reporting/screenshots.ts index d7bd90c5e74d6..0a09c785d64a4 100644 --- a/x-pack/test/functional/apps/dashboard/group3/reporting/screenshots.ts +++ b/x-pack/test/functional/apps/dashboard/group3/reporting/screenshots.ts @@ -155,7 +155,6 @@ export default function ({ }); }); - // FLAKY: https://github.com/elastic/kibana/issues/183566 describe.skip('Preserve Layout', () => { before(async () => { await loadEcommerce(); @@ -172,10 +171,10 @@ export default function ({ await PageObjects.dashboard.loadSavedDashboard('Ecom Dashboard'); await PageObjects.reporting.openExportTab(); await PageObjects.reporting.clickGenerateReportButton(); - await PageObjects.share.closeShareModal(); const url = await PageObjects.reporting.getReportURL(60000); const res = await PageObjects.reporting.getResponse(url ?? ''); + await PageObjects.share.closeShareModal(); expect(res.status).to.equal(200); expect(res.get('content-type')).to.equal('application/pdf'); diff --git a/x-pack/test/functional/apps/discover/reporting.ts b/x-pack/test/functional/apps/discover/reporting.ts index cc5a198cb5416..61ddea54a7cb1 100644 --- a/x-pack/test/functional/apps/discover/reporting.ts +++ b/x-pack/test/functional/apps/discover/reporting.ts @@ -36,14 +36,14 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await browser.refresh(); }; - const getReport = async () => { + const getReport = async ({ timeout } = { timeout: 60 * 1000 }) => { // close any open notification toasts await toasts.dismissAll(); await PageObjects.reporting.openExportTab(); await PageObjects.reporting.clickGenerateReportButton(); - const url = await PageObjects.reporting.getReportURL(60000); + const url = await PageObjects.reporting.getReportURL(timeout); const res = await PageObjects.reporting.getResponse(url ?? ''); expect(res.status).to.equal(200); @@ -173,7 +173,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.discover.saveSearch('large export'); // match file length, the beginning and the end of the csv file contents - const { text: csvFile } = await getReport(); + const { text: csvFile } = await getReport({ timeout: 80 * 1000 }); expect(csvFile.length).to.be(4826973); expectSnapshot(csvFile.slice(0, 5000)).toMatch(); expectSnapshot(csvFile.slice(-5000)).toMatch(); diff --git a/x-pack/test/functional/apps/ml/data_visualizer/index.ts b/x-pack/test/functional/apps/ml/data_visualizer/index.ts index e5b1cbab24809..bddbcdfb95370 100644 --- a/x-pack/test/functional/apps/ml/data_visualizer/index.ts +++ b/x-pack/test/functional/apps/ml/data_visualizer/index.ts @@ -35,6 +35,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./index_data_visualizer_random_sampler')); loadTestFile(require.resolve('./index_data_visualizer_filters')); loadTestFile(require.resolve('./index_data_visualizer_grid_in_discover')); + loadTestFile(require.resolve('./index_data_visualizer_grid_in_discover_trial')); loadTestFile(require.resolve('./index_data_visualizer_grid_in_dashboard')); loadTestFile(require.resolve('./index_data_visualizer_actions_panel')); loadTestFile(require.resolve('./index_data_visualizer_data_view_management')); diff --git a/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_grid_in_discover.ts b/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_grid_in_discover.ts index 7c1e2a1a8f946..14e16d5929779 100644 --- a/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_grid_in_discover.ts +++ b/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_grid_in_discover.ts @@ -28,24 +28,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const startTime = 'Jan 1, 2016 @ 00:00:00.000'; const endTime = 'Nov 1, 2020 @ 00:00:00.000'; - function runTestsWhenDisabled(testData: TestData) { - it('should not show view mode toggle or Field stats table', async function () { - await PageObjects.common.navigateToApp('discover'); - if (testData.isSavedSearch) { - await retry.tryForTime(2 * 1000, async () => { - await PageObjects.discover.loadSavedSearch(testData.sourceIndexOrSavedSearch); - }); - } else { - await dataViews.switchToAndValidate(testData.sourceIndexOrSavedSearch); - } - - await PageObjects.timePicker.setAbsoluteRange(startTime, endTime); - - await PageObjects.discover.assertViewModeToggleNotExists(); - await PageObjects.discover.assertFieldStatsTableNotExists(); - }); - } - function runTests(testData: TestData) { describe(`with ${testData.suiteTitle}`, function () { it(`displays the 'Field statistics' table content correctly`, async function () { @@ -128,14 +110,5 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { runTests(farequoteLuceneFiltersSearchTestData); runTests(sampleLogTestData); }); - - describe('when disabled', function () { - before(async function () { - // Ensure that the setting is set to default state which is false - await ml.testResources.setAdvancedSettingProperty(SHOW_FIELD_STATISTICS, false); - }); - - runTestsWhenDisabled(farequoteDataViewTestData); - }); }); } diff --git a/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_grid_in_discover_basic.ts b/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_grid_in_discover_basic.ts new file mode 100644 index 0000000000000..7d7e5dfe0760f --- /dev/null +++ b/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_grid_in_discover_basic.ts @@ -0,0 +1,70 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../ftr_provider_context'; +import { TestData } from './types'; + +const SHOW_FIELD_STATISTICS = 'discover:showFieldStatistics'; +import { farequoteDataViewTestData } from './index_test_data'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const PageObjects = getPageObjects(['common', 'discover', 'timePicker', 'settings']); + const ml = getService('ml'); + const retry = getService('retry'); + const dataViews = getService('dataViews'); + + const startTime = 'Jan 1, 2016 @ 00:00:00.000'; + const endTime = 'Nov 1, 2020 @ 00:00:00.000'; + + function runTestsWhenDisabled(testData: TestData) { + it('should not show view mode toggle or Field stats table', async function () { + await PageObjects.common.navigateToApp('discover'); + if (testData.isSavedSearch) { + await retry.tryForTime(2 * 1000, async () => { + await PageObjects.discover.loadSavedSearch(testData.sourceIndexOrSavedSearch); + }); + } else { + await dataViews.switchToAndValidate(testData.sourceIndexOrSavedSearch); + } + + await PageObjects.timePicker.setAbsoluteRange(startTime, endTime); + + await PageObjects.discover.assertViewModeToggleNotExists(); + await PageObjects.discover.assertFieldStatsTableNotExists(); + }); + } + + describe('field statistics in Discover (basic license)', function () { + before(async function () { + await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_module_sample_logs', '@timestamp'); + await ml.testResources.createSavedSearchFarequoteKueryIfNeeded(); + await ml.testResources.createSavedSearchFarequoteLuceneIfNeeded(); + await ml.testResources.createSavedSearchFarequoteFilterAndLuceneIfNeeded(); + await ml.testResources.createSavedSearchFarequoteFilterAndKueryIfNeeded(); + + await ml.securityUI.loginAsMlPowerUser(); + }); + + after(async function () { + await ml.testResources.clearAdvancedSettingProperty(SHOW_FIELD_STATISTICS); + await ml.testResources.deleteSavedSearches(); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); + }); + + describe('when disabled', function () { + before(async function () { + // Ensure that the setting is set to default state which is false + await ml.testResources.setAdvancedSettingProperty(SHOW_FIELD_STATISTICS, false); + }); + + runTestsWhenDisabled(farequoteDataViewTestData); + }); + }); +} diff --git a/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_grid_in_discover_trial.ts b/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_grid_in_discover_trial.ts new file mode 100644 index 0000000000000..9a1429805a18f --- /dev/null +++ b/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_grid_in_discover_trial.ts @@ -0,0 +1,70 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../ftr_provider_context'; +import { TestData } from './types'; + +const SHOW_FIELD_STATISTICS = 'discover:showFieldStatistics'; +import { farequoteDataViewTestData } from './index_test_data'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const PageObjects = getPageObjects(['common', 'discover', 'timePicker', 'settings']); + const ml = getService('ml'); + const retry = getService('retry'); + const dataViews = getService('dataViews'); + + const startTime = 'Jan 1, 2016 @ 00:00:00.000'; + const endTime = 'Nov 1, 2020 @ 00:00:00.000'; + + function runTestsWhenDisabled(testData: TestData) { + it('should show view mode toggle but not Field stats tab', async function () { + await PageObjects.common.navigateToApp('discover'); + if (testData.isSavedSearch) { + await retry.tryForTime(2 * 1000, async () => { + await PageObjects.discover.loadSavedSearch(testData.sourceIndexOrSavedSearch); + }); + } else { + await dataViews.switchToAndValidate(testData.sourceIndexOrSavedSearch); + } + + await PageObjects.timePicker.setAbsoluteRange(startTime, endTime); + + await PageObjects.discover.assertViewModeToggleExists(); + await PageObjects.discover.assertFieldStatsTableNotExists(); + }); + } + + describe('field statistics in Discover (trial license)', function () { + before(async function () { + await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); + await ml.testResources.createDataViewIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createDataViewIfNeeded('ft_module_sample_logs', '@timestamp'); + await ml.testResources.createSavedSearchFarequoteKueryIfNeeded(); + await ml.testResources.createSavedSearchFarequoteLuceneIfNeeded(); + await ml.testResources.createSavedSearchFarequoteFilterAndLuceneIfNeeded(); + await ml.testResources.createSavedSearchFarequoteFilterAndKueryIfNeeded(); + + await ml.securityUI.loginAsMlPowerUser(); + }); + + after(async function () { + await ml.testResources.clearAdvancedSettingProperty(SHOW_FIELD_STATISTICS); + await ml.testResources.deleteSavedSearches(); + await ml.testResources.deleteDataViewByTitle('ft_farequote'); + }); + + describe('when disabled', function () { + before(async function () { + // Ensure that the setting is set to default state which is false + await ml.testResources.setAdvancedSettingProperty(SHOW_FIELD_STATISTICS, false); + }); + + runTestsWhenDisabled(farequoteDataViewTestData); + }); + }); +} diff --git a/x-pack/test/functional/apps/rollup_job/hybrid_index_pattern.js b/x-pack/test/functional/apps/rollup_job/hybrid_index_pattern.js index a42fc0fde8cbe..799274968167c 100644 --- a/x-pack/test/functional/apps/rollup_job/hybrid_index_pattern.js +++ b/x-pack/test/functional/apps/rollup_job/hybrid_index_pattern.js @@ -17,7 +17,9 @@ export default function ({ getService, getPageObjects }) { const PageObjects = getPageObjects(['common', 'settings']); const esDeleteAllIndices = getService('esDeleteAllIndices'); - describe('hybrid index pattern', function () { + // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/183975 + // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/183976 + describe.skip('hybrid index pattern', function () { //Since rollups can only be created once with the same name (even if you delete it), //we add the Date.now() to avoid name collision if you run the tests locally back to back. const rollupJobName = `hybrid-index-pattern-test-rollup-job-${Date.now()}`; diff --git a/x-pack/test/functional/apps/rollup_job/rollup_jobs.js b/x-pack/test/functional/apps/rollup_job/rollup_jobs.js index 1b2ba0457e02b..3c33c9c31bc6b 100644 --- a/x-pack/test/functional/apps/rollup_job/rollup_jobs.js +++ b/x-pack/test/functional/apps/rollup_job/rollup_jobs.js @@ -23,7 +23,12 @@ export default function ({ getService, getPageObjects }) { remoteEs = getService('remoteEs'); } - describe('rollup job', function () { + // FLAKY: https://github.com/elastic/kibana/issues/183925 + // FLAKY: https://github.com/elastic/kibana/issues/183926 + // FLAKY: https://github.com/elastic/kibana/issues/183927 + // FLAKY: https://github.com/elastic/kibana/issues/183928 + // FLAKY: https://github.com/elastic/kibana/issues/104569 + describe.skip('rollup job', function () { // Since rollups can only be created once with the same name (even if you delete it), // we add the Date.now() to avoid name collision. const rollupJobName = 'rollup-to-be-' + Date.now(); diff --git a/x-pack/test/functional/apps/rollup_job/tsvb.js b/x-pack/test/functional/apps/rollup_job/tsvb.js index 957b33618d9cf..e7ad485224389 100644 --- a/x-pack/test/functional/apps/rollup_job/tsvb.js +++ b/x-pack/test/functional/apps/rollup_job/tsvb.js @@ -24,7 +24,9 @@ export default function ({ getService, getPageObjects }) { const fromTime = 'Oct 15, 2019 @ 00:00:01.000'; const toTime = 'Oct 15, 2019 @ 19:31:44.000'; - describe('tsvb integration', function () { + // FLAKY: https://github.com/elastic/kibana/issues/56816 + // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/168267 + describe.skip('tsvb integration', function () { //Since rollups can only be created once with the same name (even if you delete it), //we add the Date.now() to avoid name collision if you run the tests locally back to back. const rollupJobName = `tsvb-test-rollup-job-${Date.now()}`; diff --git a/x-pack/test/functional/apps/search_playground/config.ts b/x-pack/test/functional/apps/search_playground/config.ts new file mode 100644 index 0000000000000..d0d07ff200281 --- /dev/null +++ b/x-pack/test/functional/apps/search_playground/config.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile(require.resolve('../../config.base.js')); + + return { + ...functionalConfig.getAll(), + testFiles: [require.resolve('.')], + }; +} diff --git a/x-pack/plugins/reporting/server/lib/store/ilm_policy_manager/constants.ts b/x-pack/test/functional/apps/search_playground/index.ts similarity index 50% rename from x-pack/plugins/reporting/server/lib/store/ilm_policy_manager/constants.ts rename to x-pack/test/functional/apps/search_playground/index.ts index cbbf21094d61f..f15cbe9179868 100644 --- a/x-pack/plugins/reporting/server/lib/store/ilm_policy_manager/constants.ts +++ b/x-pack/test/functional/apps/search_playground/index.ts @@ -4,15 +4,10 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { FtrProviderContext } from '../../ftr_provider_context'; -import type { IlmPutLifecycleRequest } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; - -export const reportingIlmPolicy: IlmPutLifecycleRequest['body'] = { - policy: { - phases: { - hot: { - actions: {}, - }, - }, - }, -}; +export default function ({ loadTestFile }: FtrProviderContext) { + describe('playground', async () => { + loadTestFile(require.resolve('./playground_overview.ess.ts')); + }); +} diff --git a/x-pack/test/functional/apps/search_playground/playground_overview.ess.ts b/x-pack/test/functional/apps/search_playground/playground_overview.ess.ts new file mode 100644 index 0000000000000..48f6d5e13cf88 --- /dev/null +++ b/x-pack/test/functional/apps/search_playground/playground_overview.ess.ts @@ -0,0 +1,94 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../ftr_provider_context'; +import { createOpenAIConnector } from './utils/create_openai_connector'; +import { MachineLearningCommonAPIProvider } from '../../services/ml/common_api'; + +const indexName = 'basic_index'; +const esArchiveIndex = 'test/api_integration/fixtures/es_archiver/index_patterns/basic_index'; + +export default function (ftrContext: FtrProviderContext) { + const { getService, getPageObjects } = ftrContext; + const pageObjects = getPageObjects(['common', 'searchPlayground']); + const commonAPI = MachineLearningCommonAPIProvider(ftrContext); + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + const createIndex = async () => await esArchiver.load(esArchiveIndex); + let removeOpenAIConnector: () => Promise; + const createConnector = async () => { + removeOpenAIConnector = await createOpenAIConnector({ + supertest, + requestHeader: commonAPI.getCommonRequestHeader(), + }); + }; + + describe('Playground Overview', () => { + before(async () => { + await pageObjects.common.navigateToApp('enterpriseSearchApplications/playground'); + }); + + after(async () => { + await esArchiver.unload(esArchiveIndex); + await removeOpenAIConnector?.(); + }); + + describe('start chat page', () => { + it('playground app is loaded', async () => { + await pageObjects.searchPlayground.PlaygroundStartChatPage.expectPlaygroundStartChatPageComponentsToExist(); + await pageObjects.searchPlayground.PlaygroundStartChatPage.expectPlaygroundHeaderComponentsToExist(); + }); + + it('show no index callout', async () => { + await pageObjects.searchPlayground.PlaygroundStartChatPage.expectNoIndexCalloutExists(); + await pageObjects.searchPlayground.PlaygroundStartChatPage.expectCreateIndexButtonToExists(); + }); + + it('hide no index callout when index added', async () => { + await createIndex(); + await pageObjects.searchPlayground.PlaygroundStartChatPage.expectSelectIndex(indexName); + }); + + it('show add connector button', async () => { + await pageObjects.searchPlayground.PlaygroundStartChatPage.expectAddConnectorButtonExists(); + }); + + it('click add connector button opens connector flyout', async () => { + await pageObjects.searchPlayground.PlaygroundStartChatPage.expectOpenConnectorPagePlayground(); + }); + + it('hide gen ai panel when connector exists', async () => { + await pageObjects.searchPlayground.PlaygroundStartChatPage.expectHideGenAIPanelConnector( + createConnector + ); + }); + + it('show chat page', async () => { + await pageObjects.searchPlayground.PlaygroundStartChatPage.expectSelectIndex(indexName); + await pageObjects.searchPlayground.PlaygroundStartChatPage.expectToStartChatPage(); + }); + }); + + describe('chat page', () => { + it('chat works', async () => { + await pageObjects.searchPlayground.PlaygroundChatPage.expectChatWorks(); + }); + + it('open view code', async () => { + await pageObjects.searchPlayground.PlaygroundChatPage.expectOpenViewCode(); + }); + + it('show fields and code in view query', async () => { + await pageObjects.searchPlayground.PlaygroundChatPage.expectViewQueryHasFields(); + }); + + it('show edit context', async () => { + await pageObjects.searchPlayground.PlaygroundChatPage.expectEditContextOpens(); + }); + }); + }); +} diff --git a/x-pack/test/functional/apps/search_playground/utils/create_openai_connector.ts b/x-pack/test/functional/apps/search_playground/utils/create_openai_connector.ts new file mode 100644 index 0000000000000..864e424664785 --- /dev/null +++ b/x-pack/test/functional/apps/search_playground/utils/create_openai_connector.ts @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type SuperTest from 'supertest'; + +export async function createOpenAIConnector({ + supertest, + requestHeader = {}, + apiKeyHeader = {}, +}: { + supertest: SuperTest.Agent; + requestHeader?: Record; + apiKeyHeader?: Record; +}): Promise<() => Promise> { + const config = { + apiProvider: 'OpenAI', + defaultModel: 'gpt-4', + apiUrl: 'http://localhost:3002', + }; + + const connector: { id: string } | undefined = ( + await supertest + .post('/api/actions/connector') + .set(requestHeader) + .set(apiKeyHeader) + .send({ + name: 'test Open AI', + connector_type_id: '.gen-ai', + config, + secrets: { + apiKey: 'genAiApiKey', + }, + }) + .expect(200) + ).body; + + return async () => { + if (connector) { + await supertest + .delete(`/api/actions/connector/${connector.id}`) + .set(requestHeader) + .set(apiKeyHeader) + .expect(204); + } + }; +} diff --git a/x-pack/test/functional/apps/transform/creation/runtime_mappings_saved_search/creation_runtime_mappings.ts b/x-pack/test/functional/apps/transform/creation/runtime_mappings_saved_search/creation_runtime_mappings.ts index bf763457a5490..bbdf53b3eda5c 100644 --- a/x-pack/test/functional/apps/transform/creation/runtime_mappings_saved_search/creation_runtime_mappings.ts +++ b/x-pack/test/functional/apps/transform/creation/runtime_mappings_saved_search/creation_runtime_mappings.ts @@ -251,8 +251,7 @@ export default function ({ getService }: FtrProviderContext) { ]; for (const testData of testDataList) { - // FLAKY: https://github.com/elastic/kibana/issues/183339 - describe.skip(`${testData.suiteTitle}`, function () { + describe(`${testData.suiteTitle}`, function () { after(async () => { await transform.api.deleteIndices(testData.destinationIndex); await transform.testResources.deleteDataViewByTitle(testData.destinationIndex); diff --git a/x-pack/test/functional/page_objects/index.ts b/x-pack/test/functional/page_objects/index.ts index 7a459ad74f980..155bc0901ae4d 100644 --- a/x-pack/test/functional/page_objects/index.ts +++ b/x-pack/test/functional/page_objects/index.ts @@ -53,6 +53,7 @@ import { UptimePageObject } from './uptime_page'; import { UserProfilePageProvider } from './user_profile_page'; import { WatcherPageObject } from './watcher_page'; import { SearchProfilerPageProvider } from './search_profiler_page'; +import { SearchPlaygroundPageProvider } from './search_playground_page'; // just like services, PageObjects are defined as a map of // names to Providers. Merge in Kibana's or pick specific ones @@ -93,6 +94,7 @@ export const pageObjects = { roleMappings: RoleMappingsPageProvider, rollup: RollupPageObject, searchProfiler: SearchProfilerPageProvider, + searchPlayground: SearchPlaygroundPageProvider, searchSessionsManagement: SearchSessionsPageProvider, security: SecurityPageObject, shareSavedObjectsToSpace: ShareSavedObjectsToSpacePageProvider, diff --git a/x-pack/test/functional/page_objects/search_playground_page.ts b/x-pack/test/functional/page_objects/search_playground_page.ts new file mode 100644 index 0000000000000..35e0a8cc253d3 --- /dev/null +++ b/x-pack/test/functional/page_objects/search_playground_page.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 expect from '@kbn/expect'; +import { FtrProviderContext } from '../ftr_provider_context'; + +export function SearchPlaygroundPageProvider({ getService }: FtrProviderContext) { + const testSubjects = getService('testSubjects'); + const comboBox = getService('comboBox'); + const browser = getService('browser'); + + return { + PlaygroundStartChatPage: { + async expectPlaygroundStartChatPageComponentsToExist() { + await testSubjects.existOrFail('startChatPage'); + await testSubjects.existOrFail('selectIndicesChatPanel'); + await testSubjects.existOrFail('startChatButton'); + }, + + async expectPlaygroundHeaderComponentsToExist() { + await testSubjects.existOrFail('playground-header-actions'); + await testSubjects.existOrFail('playground-documentation-link'); + }, + + async expectCreateIndexButtonToMissed() { + await testSubjects.missingOrFail('createIndexButton'); + }, + + async expectCreateIndexButtonToExists() { + await testSubjects.existOrFail('createIndexButton'); + }, + + async expectNoIndexCalloutExists() { + await testSubjects.existOrFail('createIndexCallout'); + }, + + async expectSelectIndex(indexName: string) { + await browser.refresh(); + await testSubjects.missingOrFail('createIndexCallout'); + await testSubjects.existOrFail('selectIndicesComboBox'); + await comboBox.setCustom('selectIndicesComboBox', indexName); + }, + + async expectNoIndicesFieldsWarningExists() { + await testSubjects.existOrFail('NoIndicesFieldsMessage'); + }, + + async expectAddConnectorButtonExists() { + await testSubjects.existOrFail('setupGenAIConnectorButton'); + }, + + async expectOpenConnectorPagePlayground() { + await testSubjects.click('setupGenAIConnectorButton'); + await testSubjects.existOrFail('create-connector-flyout'); + }, + + async expectHideGenAIPanelConnector(createConnector: () => Promise) { + await createConnector(); + await browser.refresh(); + await testSubjects.missingOrFail('connectToLLMChatPanel'); + }, + + async expectToStartChatPage() { + expect(await testSubjects.isEnabled('startChatButton')).to.be(true); + await testSubjects.click('startChatButton'); + await testSubjects.existOrFail('chatPage'); + }, + }, + PlaygroundChatPage: { + async expectChatWorks() { + await testSubjects.existOrFail('questionInput'); + await testSubjects.setValue('questionInput', 'test question'); + await testSubjects.click('sendQuestionButton'); + await testSubjects.existOrFail('userMessage'); + }, + + async expectOpenViewCode() { + await testSubjects.click('viewCodeActionButton'); + await testSubjects.existOrFail('viewCodeFlyout'); + await testSubjects.click('euiFlyoutCloseButton'); + }, + + async expectViewQueryHasFields() { + await testSubjects.click('viewQueryActionButton'); + await testSubjects.existOrFail('viewQueryFlyout'); + const fields = await testSubjects.findAll('queryField'); + + expect(fields.length).to.be(1); + + const codeBlock = await testSubjects.find('ViewElasticsearchQueryResult'); + const code = await codeBlock.getVisibleText(); + expect(code.replace(/ /g, '')).to.be( + '{\n"retriever":{\n"standard":{\n"query":{\n"multi_match":{\n"query":"{query}",\n"fields":[\n"baz"\n]\n}\n}\n}\n}\n}' + ); + await testSubjects.click('euiFlyoutCloseButton'); + }, + + async expectEditContextOpens() { + await testSubjects.click('editContextActionButton'); + await testSubjects.existOrFail('editContextFlyout'); + await testSubjects.click('contextFieldsSelectable_basic_index'); + await testSubjects.existOrFail('contextField'); + const fields = await testSubjects.findAll('contextField'); + + expect(fields.length).to.be(1); + await testSubjects.click('euiFlyoutCloseButton'); + }, + }, + }; +} diff --git a/x-pack/test/functional/services/aiops/log_pattern_analysis_page.ts b/x-pack/test/functional/services/aiops/log_pattern_analysis_page.ts index 76ca855b4c8ca..b7ab5951af64f 100644 --- a/x-pack/test/functional/services/aiops/log_pattern_analysis_page.ts +++ b/x-pack/test/functional/services/aiops/log_pattern_analysis_page.ts @@ -76,6 +76,17 @@ export function LogPatternAnalysisPageProvider({ getService, getPageObject }: Ft }); }, + async assertTotalCategoriesFoundDiscover(expectedMinimumCategoryCount: number) { + await retry.tryForTime(5000, async () => { + const actualText = await testSubjects.getVisibleText('dscViewModePatternAnalysisButton'); + const actualCount = Number(actualText.match(/Patterns \((.+)\)/)![1]); + expect(actualCount + 1).to.greaterThan( + expectedMinimumCategoryCount, + `Expected patterns found count to be >= '${expectedMinimumCategoryCount}' (got '${actualCount}')` + ); + }); + }, + async assertCategoryTableRows(expectedMinimumCategoryCount: number) { await retry.tryForTime(5000, async () => { const tableListContainer = await testSubjects.find('aiopsLogPatternsTable'); @@ -170,12 +181,22 @@ export function LogPatternAnalysisPageProvider({ getService, getPageObject }: Ft }); }, + async clickPatternsTab() { + await testSubjects.click('dscViewModePatternAnalysisButton'); + }, + async assertLogPatternAnalysisFlyoutExists() { await retry.tryForTime(30 * 1000, async () => { await testSubjects.existOrFail('mlJobSelectorFlyoutBody'); }); }, + async assertLogPatternAnalysisTabContentsExists() { + await retry.tryForTime(30 * 1000, async () => { + await testSubjects.existOrFail('aiopsLogPatternsTable'); + }); + }, + async assertLogPatternAnalysisFlyoutDoesNotExist() { await retry.tryForTime(30 * 1000, async () => { await testSubjects.missingOrFail('mlJobSelectorFlyoutBody'); @@ -210,5 +231,23 @@ export function LogPatternAnalysisPageProvider({ getService, getPageObject }: Ft await testSubjects.missingOrFail('aiopsRandomSamplerOptionsFormRow', { timeout: 1000 }); }); }, + + async setRandomSamplingOptionDiscover(option: RandomSamplerOption) { + await retry.tryForTime(20000, async () => { + await testSubjects.existOrFail('aiopsEmbeddableMenuOptionsButton'); + await testSubjects.clickWhenNotDisabled('aiopsEmbeddableMenuOptionsButton'); + + await testSubjects.clickWhenNotDisabled('aiopsRandomSamplerOptionsSelect'); + + await testSubjects.existOrFail('aiopsRandomSamplerOptionOff', { timeout: 1000 }); + await testSubjects.existOrFail('aiopsRandomSamplerOptionOnManual', { timeout: 1000 }); + await testSubjects.existOrFail('aiopsRandomSamplerOptionOnAutomatic', { timeout: 1000 }); + + await testSubjects.click(option); + + await testSubjects.clickWhenNotDisabled('aiopsEmbeddableMenuOptionsButton'); + await testSubjects.missingOrFail('aiopsRandomSamplerOptionsFormRow', { timeout: 1000 }); + }); + }, }; } diff --git a/x-pack/test/functional_basic/apps/ml/data_visualizer/group3/index.ts b/x-pack/test/functional_basic/apps/ml/data_visualizer/group3/index.ts index d2e77f9522854..3388181aea589 100644 --- a/x-pack/test/functional_basic/apps/ml/data_visualizer/group3/index.ts +++ b/x-pack/test/functional_basic/apps/ml/data_visualizer/group3/index.ts @@ -41,6 +41,11 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { '../../../../../functional/apps/ml/data_visualizer/index_data_visualizer_grid_in_discover' ) ); + loadTestFile( + require.resolve( + '../../../../../functional/apps/ml/data_visualizer/index_data_visualizer_grid_in_discover_basic' + ) + ); loadTestFile(require.resolve('./index_data_visualizer_actions_panel')); }); } diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/rules_list/rules_list.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/rules_list/rules_list.ts index 06ccb3990b69f..e3324ccbc000a 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/rules_list/rules_list.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/rules_list/rules_list.ts @@ -49,8 +49,7 @@ export default ({ getPageObjects, getPageObject, getService }: FtrProviderContex return summary; }; - // FLAKY: https://github.com/elastic/kibana/issues/157623 - describe.skip('rules list', function () { + describe('rules list', function () { const assertRulesLength = async (length: number) => { return await retry.try(async () => { const rules = await pageObjects.triggersActionsUI.getAlertsList(); diff --git a/x-pack/test/functional_with_es_ssl/plugins/alerts/public/application.tsx b/x-pack/test/functional_with_es_ssl/plugins/alerts/public/application.tsx index 62528a84d6918..e9ea670dd9c85 100644 --- a/x-pack/test/functional_with_es_ssl/plugins/alerts/public/application.tsx +++ b/x-pack/test/functional_with_es_ssl/plugins/alerts/public/application.tsx @@ -8,6 +8,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { BrowserRouter as Router } from 'react-router-dom'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import { Route } from '@kbn/shared-ux-router'; import { EuiPage, EuiText } from '@elastic/eui'; @@ -42,7 +43,12 @@ export const renderApp = ( deps: any, { appBasePath, element }: AppMountParameters ) => { - ReactDOM.render(, element); + ReactDOM.render( + + + , + element + ); return () => ReactDOM.unmountComponentAtNode(element); }; diff --git a/x-pack/test/functional_with_es_ssl/plugins/alerts/tsconfig.json b/x-pack/test/functional_with_es_ssl/plugins/alerts/tsconfig.json index 1fe0f19638722..e42ac17f305f3 100644 --- a/x-pack/test/functional_with_es_ssl/plugins/alerts/tsconfig.json +++ b/x-pack/test/functional_with_es_ssl/plugins/alerts/tsconfig.json @@ -16,5 +16,6 @@ "@kbn/alerting-plugin", "@kbn/triggers-actions-ui-plugin", "@kbn/shared-ux-router", + "@kbn/react-kibana-context-render", ] } diff --git a/x-pack/test/observability_ai_assistant_api_integration/common/config.ts b/x-pack/test/observability_ai_assistant_api_integration/common/config.ts index 351d43f4e30b2..559bb5d65dd2a 100644 --- a/x-pack/test/observability_ai_assistant_api_integration/common/config.ts +++ b/x-pack/test/observability_ai_assistant_api_integration/common/config.ts @@ -6,15 +6,15 @@ */ import { Config, FtrConfigProviderContext } from '@kbn/test'; -import supertest from 'supertest'; -import { format, UrlObject } from 'url'; +import { UrlObject } from 'url'; import { ObservabilityAIAssistantFtrConfigName } from '../configs'; import { getApmSynthtraceEsClient } from './create_synthtrace_client'; import { InheritedFtrProviderContext, InheritedServices } from './ftr_provider_context'; import { - createObservabilityAIAssistantApiClient, + getScopedApiClient, ObservabilityAIAssistantAPIClient, } from './observability_ai_assistant_api_client'; +import { editorUser, viewerUser } from './users/users'; export interface ObservabilityAIAssistantFtrConfig { name: ObservabilityAIAssistantFtrConfigName; @@ -22,10 +22,6 @@ export interface ObservabilityAIAssistantFtrConfig { kibanaConfig?: Record; } -async function getObservabilityAIAssistantAPIClient(kibanaServerUrl: string) { - return createObservabilityAIAssistantApiClient(supertest(kibanaServerUrl)); -} - export type CreateTestConfig = ReturnType; export interface CreateTest { @@ -33,8 +29,9 @@ export interface CreateTest { servers: any; services: InheritedServices & { observabilityAIAssistantAPIClient: () => Promise<{ - readUser: ObservabilityAIAssistantAPIClient; - writeUser: ObservabilityAIAssistantAPIClient; + adminUser: ObservabilityAIAssistantAPIClient; + viewerUser: ObservabilityAIAssistantAPIClient; + editorUser: ObservabilityAIAssistantAPIClient; }>; }; junit: { reportName: string }; @@ -56,7 +53,6 @@ export function createObservabilityAIAssistantAPIConfig({ const services = config.get('services') as InheritedServices; const servers = config.get('servers'); const kibanaServer = servers.kibana as UrlObject; - const kibanaServerUrl = format(kibanaServer); const apmSynthtraceKibanaClient = services.apmSynthtraceKibanaClient(); const createTest: Omit = { @@ -68,8 +64,9 @@ export function createObservabilityAIAssistantAPIConfig({ getApmSynthtraceEsClient(context, apmSynthtraceKibanaClient), observabilityAIAssistantAPIClient: async () => { return { - readUser: await getObservabilityAIAssistantAPIClient(kibanaServerUrl), - writeUser: await getObservabilityAIAssistantAPIClient(kibanaServerUrl), + adminUser: await getScopedApiClient(kibanaServer, 'elastic'), + viewerUser: await getScopedApiClient(kibanaServer, viewerUser.username), + editorUser: await getScopedApiClient(kibanaServer, editorUser.username), }; }, }, diff --git a/x-pack/test/observability_ai_assistant_api_integration/common/observability_ai_assistant_api_client.ts b/x-pack/test/observability_ai_assistant_api_integration/common/observability_ai_assistant_api_client.ts index 865620a2d028a..005815b38057a 100644 --- a/x-pack/test/observability_ai_assistant_api_integration/common/observability_ai_assistant_api_client.ts +++ b/x-pack/test/observability_ai_assistant_api_integration/common/observability_ai_assistant_api_client.ts @@ -12,8 +12,20 @@ import type { } from '@kbn/observability-ai-assistant-plugin/public'; import { formatRequest } from '@kbn/server-route-repository'; import supertest from 'supertest'; -import { format } from 'url'; import { Subtract } from 'utility-types'; +import { format, UrlObject } from 'url'; +import { kbnTestConfig } from '@kbn/test'; +import { User } from './users/users'; + +export async function getScopedApiClient(kibanaServer: UrlObject, username: User['username']) { + const { password } = kbnTestConfig.getUrlParts(); + const baseUrlWithAuth = format({ + ...kibanaServer, + auth: `${username}:${password}`, + }); + + return createObservabilityAIAssistantApiClient(supertest(baseUrlWithAuth)); +} export function createObservabilityAIAssistantApiClient(st: supertest.Agent) { return ( diff --git a/x-pack/test/observability_ai_assistant_api_integration/common/users/create_users_and_roles.ts b/x-pack/test/observability_ai_assistant_api_integration/common/users/create_users_and_roles.ts new file mode 100644 index 0000000000000..1492fa68114a2 --- /dev/null +++ b/x-pack/test/observability_ai_assistant_api_integration/common/users/create_users_and_roles.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 { InheritedFtrProviderContext } from '../ftr_provider_context'; +import { allUsers } from './users'; +import { allRoles } from './roles'; + +export async function createUsersAndRoles(getService: InheritedFtrProviderContext['getService']) { + const security = getService('security'); + const log = getService('log'); + + // create roles + await Promise.all( + allRoles.map(({ name, privileges }) => { + return security.role.create(name, privileges); + }) + ); + + // create users + await Promise.all( + allUsers.map((user) => { + log.info(`Creating user: ${user.username} with roles: ${user.roles.join(', ')}`); + return security.user.create(user.username, { + password: user.password, + roles: user.roles, + }); + }) + ); +} diff --git a/x-pack/test/observability_ai_assistant_api_integration/common/users/roles.ts b/x-pack/test/observability_ai_assistant_api_integration/common/users/roles.ts new file mode 100644 index 0000000000000..ec5c9daac3ea9 --- /dev/null +++ b/x-pack/test/observability_ai_assistant_api_integration/common/users/roles.ts @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +// Example role: +// export const allAccessRole: Role = { +// name: 'all_access', +// privileges: { +// elasticsearch: { +// indices: [ +// { +// names: ['*'], +// privileges: ['all'], +// }, +// ], +// }, +// kibana: [ +// { +// feature: { +// apm: ['all'], +// actions: ['all'], +// }, +// spaces: ['*'], +// }, +// ], +// }, +// }; + +export interface Role { + name: string; + privileges: { + elasticsearch?: { + cluster?: string[]; + indices?: Array<{ + names: string[]; + privileges: string[]; + }>; + }; + kibana?: Array<{ + spaces: string[]; + base?: string[]; + feature?: { + [featureId: string]: string[]; + }; + }>; + }; +} + +export const allRoles = []; diff --git a/x-pack/test/observability_ai_assistant_api_integration/common/users/users.ts b/x-pack/test/observability_ai_assistant_api_integration/common/users/users.ts new file mode 100644 index 0000000000000..b6fa38e52e60b --- /dev/null +++ b/x-pack/test/observability_ai_assistant_api_integration/common/users/users.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { kbnTestConfig } from '@kbn/test'; +const password = kbnTestConfig.getUrlParts().password!; + +export interface User { + username: 'elastic' | 'editor' | 'viewer'; + password: string; + roles: string[]; +} + +export const editorUser: User = { + username: 'editor', + password, + roles: ['editor'], +}; + +export const viewerUser: User = { + username: 'viewer', + password, + roles: ['viewer'], +}; + +export const allUsers = [editorUser, viewerUser]; diff --git a/x-pack/test/observability_ai_assistant_api_integration/tests/complete/complete.spec.ts b/x-pack/test/observability_ai_assistant_api_integration/tests/complete/complete.spec.ts index 38303c3a53076..01f6e8cdd7bce 100644 --- a/x-pack/test/observability_ai_assistant_api_integration/tests/complete/complete.spec.ts +++ b/x-pack/test/observability_ai_assistant_api_integration/tests/complete/complete.spec.ts @@ -302,7 +302,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { )[0]?.conversation.id; await observabilityAIAssistantAPIClient - .writeUser({ + .adminUser({ endpoint: 'DELETE /internal/observability_ai_assistant/conversation/{conversationId}', params: { path: { @@ -378,7 +378,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { ).to.eql(0); const conversations = await observabilityAIAssistantAPIClient - .writeUser({ + .editorUser({ endpoint: 'POST /internal/observability_ai_assistant/conversations', }) .expect(200); @@ -422,7 +422,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { .complete(); const createResponse = await observabilityAIAssistantAPIClient - .writeUser({ + .editorUser({ endpoint: 'POST /internal/observability_ai_assistant/chat/complete', params: { body: { @@ -440,7 +440,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { conversationCreatedEvent = getConversationCreatedEvent(createResponse.body); const conversationId = conversationCreatedEvent.conversation.id; - const fullConversation = await observabilityAIAssistantAPIClient.readUser({ + const fullConversation = await observabilityAIAssistantAPIClient.editorUser({ endpoint: 'GET /internal/observability_ai_assistant/conversation/{conversationId}', params: { path: { @@ -454,7 +454,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { .complete(); const updatedResponse = await observabilityAIAssistantAPIClient - .writeUser({ + .editorUser({ endpoint: 'POST /internal/observability_ai_assistant/chat/complete', params: { body: { @@ -484,7 +484,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { after(async () => { await observabilityAIAssistantAPIClient - .writeUser({ + .editorUser({ endpoint: 'DELETE /internal/observability_ai_assistant/conversation/{conversationId}', params: { path: { diff --git a/x-pack/test/observability_ai_assistant_api_integration/tests/connectors/connectors.spec.ts b/x-pack/test/observability_ai_assistant_api_integration/tests/connectors/connectors.spec.ts index d51edffc9a1a8..d334251d9114e 100644 --- a/x-pack/test/observability_ai_assistant_api_integration/tests/connectors/connectors.spec.ts +++ b/x-pack/test/observability_ai_assistant_api_integration/tests/connectors/connectors.spec.ts @@ -24,14 +24,14 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('Returns a 2xx for enterprise license', async () => { await observabilityAIAssistantAPIClient - .readUser({ + .editorUser({ endpoint: 'GET /internal/observability_ai_assistant/connectors', }) .expect(200); }); it('returns an empty list of connectors', async () => { - const res = await observabilityAIAssistantAPIClient.readUser({ + const res = await observabilityAIAssistantAPIClient.editorUser({ endpoint: 'GET /internal/observability_ai_assistant/connectors', }); @@ -55,7 +55,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { }) .expect(200); - const res = await observabilityAIAssistantAPIClient.readUser({ + const res = await observabilityAIAssistantAPIClient.editorUser({ endpoint: 'GET /internal/observability_ai_assistant/connectors', }); diff --git a/x-pack/test/observability_ai_assistant_api_integration/tests/conversations/conversations.spec.ts b/x-pack/test/observability_ai_assistant_api_integration/tests/conversations/conversations.spec.ts index 85c9eb725d47c..91a418b3000ee 100644 --- a/x-pack/test/observability_ai_assistant_api_integration/tests/conversations/conversations.spec.ts +++ b/x-pack/test/observability_ai_assistant_api_integration/tests/conversations/conversations.spec.ts @@ -48,7 +48,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { describe('without conversations', () => { it('returns no conversations when listing', async () => { const response = await observabilityAIAssistantAPIClient - .readUser({ + .editorUser({ endpoint: 'POST /internal/observability_ai_assistant/conversations', }) .expect(200); @@ -58,7 +58,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('returns a 404 for updating conversations', async () => { await observabilityAIAssistantAPIClient - .writeUser({ + .editorUser({ endpoint: 'PUT /internal/observability_ai_assistant/conversation/{conversationId}', params: { path: { @@ -74,7 +74,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('returns a 404 for retrieving a conversation', async () => { await observabilityAIAssistantAPIClient - .readUser({ + .editorUser({ endpoint: 'GET /internal/observability_ai_assistant/conversation/{conversationId}', params: { path: { @@ -92,7 +92,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { >; before(async () => { createResponse = await observabilityAIAssistantAPIClient - .writeUser({ + .editorUser({ endpoint: 'POST /internal/observability_ai_assistant/conversation', params: { body: { @@ -105,7 +105,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { after(async () => { await observabilityAIAssistantAPIClient - .writeUser({ + .editorUser({ endpoint: 'DELETE /internal/observability_ai_assistant/conversation/{conversationId}', params: { path: { @@ -116,7 +116,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { .expect(200); await observabilityAIAssistantAPIClient - .writeUser({ + .editorUser({ endpoint: 'GET /internal/observability_ai_assistant/conversation/{conversationId}', params: { path: { @@ -141,14 +141,14 @@ export default function ApiTest({ getService }: FtrProviderContext) { namespace: 'default', public: conversationCreate.public, user: { - name: 'elastic', + name: 'editor', }, }); }); it('returns a 404 for updating a non-existing conversation', async () => { await observabilityAIAssistantAPIClient - .writeUser({ + .editorUser({ endpoint: 'PUT /internal/observability_ai_assistant/conversation/{conversationId}', params: { path: { @@ -164,7 +164,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('returns a 404 for retrieving a non-existing conversation', async () => { await observabilityAIAssistantAPIClient - .readUser({ + .editorUser({ endpoint: 'GET /internal/observability_ai_assistant/conversation/{conversationId}', params: { path: { @@ -177,7 +177,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('returns the conversation that was created', async () => { const response = await observabilityAIAssistantAPIClient - .readUser({ + .editorUser({ endpoint: 'GET /internal/observability_ai_assistant/conversation/{conversationId}', params: { path: { @@ -192,7 +192,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('returns the created conversation when listing', async () => { const response = await observabilityAIAssistantAPIClient - .readUser({ + .editorUser({ endpoint: 'POST /internal/observability_ai_assistant/conversations', }) .expect(200); @@ -210,7 +210,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { before(async () => { updateResponse = await observabilityAIAssistantAPIClient - .writeUser({ + .editorUser({ endpoint: 'PUT /internal/observability_ai_assistant/conversation/{conversationId}', params: { path: { @@ -234,7 +234,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('returns the updated conversation after get', async () => { const updateAfterCreateResponse = await observabilityAIAssistantAPIClient - .writeUser({ + .editorUser({ endpoint: 'GET /internal/observability_ai_assistant/conversation/{conversationId}', params: { path: { diff --git a/x-pack/test/observability_ai_assistant_api_integration/tests/index.ts b/x-pack/test/observability_ai_assistant_api_integration/tests/index.ts index 20e8338a55a3f..e0312d2f76019 100644 --- a/x-pack/test/observability_ai_assistant_api_integration/tests/index.ts +++ b/x-pack/test/observability_ai_assistant_api_integration/tests/index.ts @@ -6,6 +6,7 @@ */ import globby from 'globby'; import path from 'path'; +import { createUsersAndRoles } from '../common/users/create_users_and_roles'; import { FtrProviderContext } from '../common/ftr_provider_context'; const cwd = path.join(__dirname); @@ -18,6 +19,11 @@ export default function observabilityAIAssistantApiIntegrationTests({ const filePattern = '**/*.spec.ts'; const tests = globby.sync(filePattern, { cwd }); + // Creates roles and users before running tests + before(async () => { + await createUsersAndRoles(getService); + }); + tests.forEach((testName) => { describe(testName, () => { loadTestFile(require.resolve(`./${testName}`)); diff --git a/x-pack/test/observability_ai_assistant_functional/common/config.ts b/x-pack/test/observability_ai_assistant_functional/common/config.ts index 35a12f10861c4..e92bf3729cb40 100644 --- a/x-pack/test/observability_ai_assistant_functional/common/config.ts +++ b/x-pack/test/observability_ai_assistant_functional/common/config.ts @@ -7,10 +7,13 @@ import { FtrConfigProviderContext } from '@kbn/test'; import { merge } from 'lodash'; -import supertest from 'supertest'; -import { format, UrlObject } from 'url'; +import { UrlObject } from 'url'; import type { EBTHelpersContract } from '@kbn/analytics-ftr-helpers-plugin/common/types'; import { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace'; +import { + editorUser, + viewerUser, +} from '../../observability_ai_assistant_api_integration/common/users/users'; import { KibanaEBTServerProvider, KibanaEBTUIProvider, @@ -21,7 +24,7 @@ import { createObservabilityAIAssistantAPIConfig, } from '../../observability_ai_assistant_api_integration/common/config'; import { - createObservabilityAIAssistantApiClient, + getScopedApiClient, ObservabilityAIAssistantAPIClient, } from '../../observability_ai_assistant_api_integration/common/observability_ai_assistant_api_client'; import { InheritedFtrProviderContext, InheritedServices } from '../ftr_provider_context'; @@ -33,11 +36,11 @@ export interface TestConfig extends CreateTestAPI { observabilityAIAssistantUI: ( context: InheritedFtrProviderContext ) => Promise; - observabilityAIAssistantAPIClient: () => Promise< - Awaited> & { - testUser: ObservabilityAIAssistantAPIClient; - } - >; + observabilityAIAssistantAPIClient: () => Promise<{ + adminUser: ObservabilityAIAssistantAPIClient; + viewerUser: ObservabilityAIAssistantAPIClient; + editorUser: ObservabilityAIAssistantAPIClient; + }>; kibana_ebt_server: (context: InheritedFtrProviderContext) => EBTHelpersContract; kibana_ebt_ui: (context: InheritedFtrProviderContext) => EBTHelpersContract; apmSynthtraceEsClient: ( @@ -63,6 +66,8 @@ export function createTestConfig( kibanaConfig, }); + const kibanaServer = baseConfig.servers.kibana as UrlObject; + return merge( { services: testConfig.get('services'), @@ -74,17 +79,10 @@ export function createTestConfig( observabilityAIAssistantUI: (context: InheritedFtrProviderContext) => ObservabilityAIAssistantUIProvider(context), observabilityAIAssistantAPIClient: async (context: InheritedFtrProviderContext) => { - const otherUsers = await baseConfig.services.observabilityAIAssistantAPIClient(); return { - ...otherUsers, - testUser: createObservabilityAIAssistantApiClient( - supertest( - format({ - ...(baseConfig.servers.kibana as UrlObject), - auth: `test_user:changeme`, - }) - ) - ), + adminUser: await getScopedApiClient(kibanaServer, 'elastic'), + viewerUser: await getScopedApiClient(kibanaServer, viewerUser.username), + editorUser: await getScopedApiClient(kibanaServer, editorUser.username), }; }, kibana_ebt_server: KibanaEBTServerProvider, diff --git a/x-pack/test/observability_ai_assistant_functional/common/ui/index.ts b/x-pack/test/observability_ai_assistant_functional/common/ui/index.ts index 17fd5f89c7d17..b7234648c8464 100644 --- a/x-pack/test/observability_ai_assistant_functional/common/ui/index.ts +++ b/x-pack/test/observability_ai_assistant_functional/common/ui/index.ts @@ -6,17 +6,16 @@ */ import type { PathsOf, TypeAsArgs, TypeOf } from '@kbn/typed-react-router-config'; +import { kbnTestConfig } from '@kbn/test'; import type { ObservabilityAIAssistantRoutes } from '@kbn/observability-ai-assistant-app-plugin/public/routes/config'; import qs from 'query-string'; -import type { Role } from '@kbn/security-plugin-types-common'; -import { OBSERVABILITY_AI_ASSISTANT_FEATURE_ID } from '@kbn/observability-ai-assistant-plugin/common/feature'; -import { APM_SERVER_FEATURE_ID } from '@kbn/apm-plugin/server'; +import { User } from '../../../observability_ai_assistant_api_integration/common/users/users'; import type { InheritedFtrProviderContext } from '../../ftr_provider_context'; export interface ObservabilityAIAssistantUIService { pages: typeof pages; auth: { - login: () => Promise; + login: (username: User['username']) => Promise; logout: () => Promise; }; router: { @@ -54,42 +53,20 @@ export async function ObservabilityAIAssistantUIProvider({ getPageObjects, getService, }: InheritedFtrProviderContext): Promise { - const browser = getService('browser'); - const deployment = getService('deployment'); - const security = getService('security'); - const pageObjects = getPageObjects(['common']); - - const roleDefinition: Role = { - name: 'observability-ai-assistant-functional-test-role', - elasticsearch: { - cluster: [], - indices: [], - run_as: [], - }, - kibana: [ - { - spaces: ['*'], - base: [], - feature: { - actions: ['all'], - [APM_SERVER_FEATURE_ID]: ['all'], - [OBSERVABILITY_AI_ASSISTANT_FEATURE_ID]: ['all'], - }, - }, - ], - }; + const pageObjects = getPageObjects(['common', 'security']); return { pages, auth: { - login: async () => { - await browser.navigateTo(deployment.getHostPort()); - await security.role.create(roleDefinition.name, roleDefinition); - await security.testUser.setRoles([roleDefinition.name, 'apm_user', 'viewer']); // performs a page reload + login: async (username: string) => { + const { password } = kbnTestConfig.getUrlParts(); + + await pageObjects.security.login(username, password, { + expectSpaceSelector: false, + }); }, logout: async () => { - await security.role.delete(roleDefinition.name); - await security.testUser.restoreDefaults(); + await pageObjects.security.forceLogout(); }, }, router: { diff --git a/x-pack/test/observability_ai_assistant_functional/tests/contextual_insights/index.spec.ts b/x-pack/test/observability_ai_assistant_functional/tests/contextual_insights/index.spec.ts index b1edc25053cc8..4a6992b6362e6 100644 --- a/x-pack/test/observability_ai_assistant_functional/tests/contextual_insights/index.spec.ts +++ b/x-pack/test/observability_ai_assistant_functional/tests/contextual_insights/index.spec.ts @@ -101,7 +101,7 @@ export default function ApiTest({ getService, getPageObjects }: FtrProviderConte await Promise.all([ createSynthtraceErrors(), // create synthtrace - ui.auth.login(), // login + ui.auth.login('editor'), // login ]); }); @@ -113,14 +113,16 @@ export default function ApiTest({ getService, getPageObjects }: FtrProviderConte ]); }); - describe('when there are no connectors', () => { + // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/184029 + describe.skip('when there are no connectors', () => { it('should not show the contextual insight component', async () => { await navigateToError(); await testSubjects.missingOrFail(ui.pages.contextualInsights.button); }); }); - describe('when there are connectors', () => { + // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/184071 + describe.skip('when there are connectors', () => { let proxy: LlmProxy; before(async () => { diff --git a/x-pack/test/observability_ai_assistant_functional/tests/conversations/index.spec.ts b/x-pack/test/observability_ai_assistant_functional/tests/conversations/index.spec.ts index 670903591287f..b7c33db0a4122 100644 --- a/x-pack/test/observability_ai_assistant_functional/tests/conversations/index.spec.ts +++ b/x-pack/test/observability_ai_assistant_functional/tests/conversations/index.spec.ts @@ -31,17 +31,17 @@ export default function ApiTest({ getService, getPageObjects }: FtrProviderConte const toasts = getService('toasts'); - const { header } = getPageObjects(['header', 'common']); + const { header } = getPageObjects(['header', 'security']); const flyoutService = getService('flyout'); async function deleteConversations() { - const response = await observabilityAIAssistantAPIClient.testUser({ + const response = await observabilityAIAssistantAPIClient.editorUser({ endpoint: 'POST /internal/observability_ai_assistant/conversations', }); for (const conversation of response.body.conversations) { - await observabilityAIAssistantAPIClient.testUser({ + await observabilityAIAssistantAPIClient.editorUser({ endpoint: `DELETE /internal/observability_ai_assistant/conversation/{conversationId}`, params: { path: { @@ -53,7 +53,7 @@ export default function ApiTest({ getService, getPageObjects }: FtrProviderConte } async function deleteConnectors() { - const response = await observabilityAIAssistantAPIClient.testUser({ + const response = await observabilityAIAssistantAPIClient.editorUser({ endpoint: 'GET /internal/observability_ai_assistant/connectors', }); @@ -66,7 +66,7 @@ export default function ApiTest({ getService, getPageObjects }: FtrProviderConte } async function createOldConversation() { - await observabilityAIAssistantAPIClient.testUser({ + await observabilityAIAssistantAPIClient.editorUser({ endpoint: 'POST /internal/observability_ai_assistant/conversation', params: { body: { @@ -150,7 +150,7 @@ export default function ApiTest({ getService, getPageObjects }: FtrProviderConte proxy = await createLlmProxy(log); - await ui.auth.login(); + await ui.auth.login('editor'); await ui.router.goto('/conversations/new', { path: {}, query: {} }); }); @@ -204,7 +204,7 @@ export default function ApiTest({ getService, getPageObjects }: FtrProviderConte }); it('creates a connector', async () => { - const response = await observabilityAIAssistantAPIClient.testUser({ + const response = await observabilityAIAssistantAPIClient.editorUser({ endpoint: 'GET /internal/observability_ai_assistant/connectors', }); @@ -264,7 +264,7 @@ export default function ApiTest({ getService, getPageObjects }: FtrProviderConte }); it('creates a conversation and updates the URL', async () => { - const response = await observabilityAIAssistantAPIClient.testUser({ + const response = await observabilityAIAssistantAPIClient.editorUser({ endpoint: 'POST /internal/observability_ai_assistant/conversations', }); @@ -331,7 +331,7 @@ export default function ApiTest({ getService, getPageObjects }: FtrProviderConte }); it('does not create another conversation', async () => { - const response = await observabilityAIAssistantAPIClient.testUser({ + const response = await observabilityAIAssistantAPIClient.editorUser({ endpoint: 'POST /internal/observability_ai_assistant/conversations', }); @@ -339,7 +339,7 @@ export default function ApiTest({ getService, getPageObjects }: FtrProviderConte }); it('appends to the existing one', async () => { - const response = await observabilityAIAssistantAPIClient.testUser({ + const response = await observabilityAIAssistantAPIClient.editorUser({ endpoint: 'POST /internal/observability_ai_assistant/conversations', }); @@ -398,7 +398,7 @@ export default function ApiTest({ getService, getPageObjects }: FtrProviderConte expect(conversation.conversation.title).to.eql('My title'); expect(conversation.namespace).to.eql('default'); expect(conversation.public).to.eql(false); - expect(conversation.user?.name).to.eql('test_user'); + expect(conversation.user?.name).to.eql('editor'); const { messages } = conversation; @@ -475,7 +475,7 @@ export default function ApiTest({ getService, getPageObjects }: FtrProviderConte expect(conversation.conversation.title).to.eql('My old conversation'); expect(conversation.namespace).to.eql('default'); expect(conversation.public).to.eql(false); - expect(conversation.user?.name).to.eql('test_user'); + expect(conversation.user?.name).to.eql('editor'); const { messages } = conversation; diff --git a/x-pack/test/observability_ai_assistant_functional/tests/index.ts b/x-pack/test/observability_ai_assistant_functional/tests/index.ts index 9a2e4902d7366..07e81d9488592 100644 --- a/x-pack/test/observability_ai_assistant_functional/tests/index.ts +++ b/x-pack/test/observability_ai_assistant_functional/tests/index.ts @@ -7,6 +7,7 @@ import globby from 'globby'; import path from 'path'; +import { createUsersAndRoles } from '../../observability_ai_assistant_api_integration/common/users/create_users_and_roles'; import { FtrProviderContext } from '../../observability_ai_assistant_api_integration/common/ftr_provider_context'; const cwd = path.join(__dirname); @@ -19,6 +20,11 @@ export default function observabilityAIAssistantFunctionalTests({ const filePattern = '**/*.spec.ts'; const tests = globby.sync(filePattern, { cwd }); + // Creates roles and users before running tests + before(async () => { + await createUsersAndRoles(getService); + }); + tests.forEach((testName) => { describe(testName, () => { loadTestFile(require.resolve(`./${testName}`)); 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 bafcb03cbe211..163c416bea314 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 @@ -131,6 +131,7 @@ export default function ({ getService }: FtrProviderContext) { 'cases-telemetry-task', 'cloud_security_posture-stats_task', 'dashboard_telemetry', + 'endpoint:complete-external-response-actions', 'endpoint:metadata-check-transforms-task', 'endpoint:user-artifact-packager', 'fleet:check-deleted-files-task', diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/datastream.ts b/x-pack/test/reporting_api_integration/reporting_and_security/datastream.ts new file mode 100644 index 0000000000000..f116110db78f1 --- /dev/null +++ b/x-pack/test/reporting_api_integration/reporting_and_security/datastream.ts @@ -0,0 +1,67 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { expect } from 'expect'; +import { FtrProviderContext } from '../ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function ({ getService }: FtrProviderContext) { + const reportingAPI = getService('reportingAPI'); + const supertest = getService('supertest'); + + describe('Data Stream', () => { + before(async () => { + await reportingAPI.initEcommerce(); + + // for this test, we don't need to wait for the job to finish or verify the result + await reportingAPI.postJob( + `/api/reporting/generate/csv_searchsource?jobParams=%28browserTimezone%3AUTC%2Ccolumns%3A%21%28%29%2CobjectType%3Asearch%2CsearchSource%3A%28fields%3A%21%28%28field%3A%27%2A%27%2Cinclude_unmapped%3Atrue%29%29%2Cfilter%3A%21%28%28meta%3A%28field%3A%27%40timestamp%27%2Cindex%3A%27logstash-%2A%27%2Cparams%3A%28%29%29%2Cquery%3A%28range%3A%28%27%40timestamp%27%3A%28format%3Astrict_date_optional_time%2Cgte%3A%272015-09-22T09%3A17%3A53.728Z%27%2Clte%3A%272015-09-22T09%3A30%3A50.786Z%27%29%29%29%29%2C%28%27%24state%27%3A%28store%3AappState%29%2Cmeta%3A%28alias%3A%21n%2Cdisabled%3A%21f%2Cindex%3A%27logstash-%2A%27%2Ckey%3Aquery%2Cnegate%3A%21f%2Ctype%3Acustom%2Cvalue%3A%27%7B%22bool%22%3A%7B%22minimum_should_match%22%3A1%2C%22should%22%3A%5B%7B%22match_phrase%22%3A%7B%22%40tags%22%3A%22info%22%7D%7D%5D%7D%7D%27%29%2Cquery%3A%28bool%3A%28minimum_should_match%3A1%2Cshould%3A%21%28%28match_phrase%3A%28%27%40tags%27%3Ainfo%29%29%29%29%29%29%29%2Cindex%3A%27logstash-%2A%27%2Cquery%3A%28language%3Akuery%2Cquery%3A%27%27%29%2Csort%3A%21%28%28%27%40timestamp%27%3A%28format%3Astrict_date_optional_time%2Corder%3Adesc%29%29%29%29%2Ctitle%3A%27A%20saved%20search%20with%20match_phrase%20filter%20and%20no%20columns%20selected%27%2Cversion%3A%278.15.0%27%29` + ); + }); + + after(async () => { + await reportingAPI.deleteAllReports(); + await reportingAPI.teardownEcommerce(); + }); + + it('uses the datastream configuration without set policy', async () => { + const { body } = await supertest + .get(`/api/index_management/data_streams/.kibana-reporting`) + .set('kbn-xsrf', 'xxx') + .set('x-elastic-internal-origin', 'xxx') + .expect(200); + + expect(body).toEqual({ + _meta: { + description: 'default kibana reporting template installed by elasticsearch', + managed: true, + }, + name: '.kibana-reporting', + indexTemplateName: '.kibana-reporting', + timeStampField: { name: '@timestamp' }, + indices: [ + { + name: expect.any(String), + uuid: expect.any(String), + managedBy: 'Index Lifecycle Management', + preferILM: true, + }, + ], + generation: 1, + health: 'green', + ilmPolicyName: 'kibana-reporting', + maxTimeStamp: 0, + privileges: { delete_index: true, manage_data_stream_lifecycle: true }, + hidden: true, + lifecycle: { enabled: true }, + nextGenerationManagedBy: 'Index Lifecycle Management', + storageSize: expect.any(String), + storageSizeBytes: expect.any(Number), + }); + }); + }); +} diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/ilm_migration_apis.ts b/x-pack/test/reporting_api_integration/reporting_and_security/ilm_migration_apis.ts index f3e1223c26084..0442917012f49 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/ilm_migration_apis.ts +++ b/x-pack/test/reporting_api_integration/reporting_and_security/ilm_migration_apis.ts @@ -42,7 +42,8 @@ export default function ({ getService }: FtrProviderContext) { cluster: ['manage_ilm'], indices: [ { names: ['ecommerce'], privileges: ['read'], allow_restricted_indices: false }, - { names: ['.reporting-*'], privileges: ['all'], allow_restricted_indices: true }, + { names: ['.reporting-*'], privileges: ['all'], allow_restricted_indices: true }, // plain indices (from old version) + { names: ['.kibana-reporting'], privileges: ['all'], allow_restricted_indices: true }, // data stream ], run_as: [], }, diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/index.ts b/x-pack/test/reporting_api_integration/reporting_and_security/index.ts index 2d968295f09be..14c33bced7601 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/index.ts +++ b/x-pack/test/reporting_api_integration/reporting_and_security/index.ts @@ -22,6 +22,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./bwc_existing_indexes')); loadTestFile(require.resolve('./security_roles_privileges')); loadTestFile(require.resolve('./generate_csv_discover')); + loadTestFile(require.resolve('./datastream')); loadTestFile(require.resolve('./csv_v2')); loadTestFile(require.resolve('./csv_v2_esql')); loadTestFile(require.resolve('./network_policy')); diff --git a/x-pack/plugins/reporting/server/lib/store/index_timestamp.ts b/x-pack/test/reporting_api_integration/services/index_timestamp.ts similarity index 100% rename from x-pack/plugins/reporting/server/lib/store/index_timestamp.ts rename to x-pack/test/reporting_api_integration/services/index_timestamp.ts diff --git a/x-pack/test/reporting_api_integration/services/scenarios.ts b/x-pack/test/reporting_api_integration/services/scenarios.ts index a2bc7e57dc8d7..253c0d36354ce 100644 --- a/x-pack/test/reporting_api_integration/services/scenarios.ts +++ b/x-pack/test/reporting_api_integration/services/scenarios.ts @@ -5,12 +5,16 @@ * 2.0. */ +import type { LoadActionPerfOptions } from '@kbn/es-archiver'; +import { INTERNAL_ROUTES } from '@kbn/reporting-common'; +import type { JobParamsCSV } from '@kbn/reporting-export-types-csv-common'; import type { JobParamsPDFDeprecated } from '@kbn/reporting-export-types-pdf-common'; import type { JobParamsPNGV2 } from '@kbn/reporting-export-types-png-common'; -import type { JobParamsCSV } from '@kbn/reporting-export-types-csv-common'; +import { + REPORTING_DATA_STREAM_WILDCARD, + REPORTING_DATA_STREAM_WILDCARD_WITH_LEGACY, +} from '@kbn/reporting-server'; import rison from '@kbn/rison'; -import { LoadActionPerfOptions } from '@kbn/es-archiver'; -import { INTERNAL_ROUTES } from '@kbn/reporting-common'; import { FtrProviderContext } from '../ftr_provider_context'; function removeWhitespace(str: string) { @@ -64,7 +68,6 @@ export function createScenarios({ getService }: Pick { await esArchiver.unload('x-pack/test/functional/es_archives/reporting/ecommerce'); await kibanaServer.importExport.unload(ecommerceSOPath); - await deleteAllReports(); }; const initLogs = async () => { @@ -211,7 +214,7 @@ export function createScenarios({ getService }: Pick { await esSupertest - .post('/.reporting*/_delete_by_query') + .post(`/${REPORTING_DATA_STREAM_WILDCARD_WITH_LEGACY}/_delete_by_query`) .send({ query: { match_all: {} } }) .expect(200); }); @@ -248,7 +251,7 @@ export function createScenarios({ getService }: Pick { }); }); - context('with category weights', () => { - it('weights risk inputs from different categories according to the category weight', async () => { - const documentId = uuidv4(); - const userSignal = buildDocument( - { 'event.kind': 'signal', 'user.name': 'user-1' }, - documentId - ); - const hostSignal = buildDocument( - { 'event.kind': 'signal', 'host.name': 'host-1' }, - documentId - ); - await indexListOfDocuments(Array(50).fill(userSignal).concat(Array(50).fill(hostSignal))); - - await createAndSyncRuleAndAlerts({ - query: `id: ${documentId}`, - alerts: 100, - riskScore: 100, - }); - const { scores } = await previewRiskScores({ - body: { - weights: [{ type: 'risk_category', value: 'category_1', host: 0.4, user: 0.8 }], - }, - }); - - expect(sanitizeScores(scores.host!)).to.eql([ - { - calculated_level: 'Low', - calculated_score: 93.2375911647125, - calculated_score_norm: 35.695861854790394, - category_1_score: 35.69586185479039, - category_1_count: 50, - id_field: 'host.name', - id_value: 'host-1', - }, - ]); - - expect(sanitizeScores(scores.user!)).to.eql([ - { - calculated_level: 'High', - calculated_score: 186.475182329425, - calculated_score_norm: 71.39172370958079, - category_1_score: 71.39172370958077, - category_1_count: 50, - id_field: 'user.name', - id_value: 'user-1', - }, - ]); - }); - }); - describe('@skipInServerless with asset criticality data', () => { const assetCriticalityRoutes = assetCriticalityRouteHelpersFactory(supertest); diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/risk_engine/trial_license_complete_tier/telemetry_usage.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/risk_engine/trial_license_complete_tier/telemetry_usage.ts index 1c3b1349a6289..3eca71c37dab5 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/risk_engine/trial_license_complete_tier/telemetry_usage.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/risk_engine/trial_license_complete_tier/telemetry_usage.ts @@ -16,6 +16,7 @@ import { riskEngineRouteHelpersFactory, cleanRiskEngine, getRiskEngineStats, + areRiskScoreIndicesEmpty, } from '../../utils'; import { FtrProviderContext } from '../../../../ftr_provider_context'; @@ -25,7 +26,6 @@ export default ({ getService }: FtrProviderContext) => { const log = getService('log'); const retry = getService('retry'); const es = getService('es'); - const createAndSyncRuleAndAlerts = createAndSyncRuleAndAlertsFactory({ supertest, log }); const riskEngineRoutes = riskEngineRouteHelpersFactory(supertest); @@ -43,6 +43,9 @@ export default ({ getService }: FtrProviderContext) => { after(async () => { await esArchiver.unload('x-pack/test/functional/es_archives/security_solution/ecs_compliant'); + await cleanRiskEngine({ kibanaServer, es, log }); + await deleteAllAlerts(supertest, log, es); + await deleteAllRules(supertest, log); }); beforeEach(async () => { @@ -51,79 +54,62 @@ export default ({ getService }: FtrProviderContext) => { await deleteAllRules(supertest, log); }); - describe('Risk engine not enabled', () => { - it('should has empty riskEngineMetrics', async () => { - await retry.try(async () => { - const stats = await getRiskEngineStats(supertest, log); - const expected = {}; - expect(stats).to.eql(expected); - }); + it('should return empty metrics when the risk engine is disabled', async () => { + await retry.try(async () => { + const stats = await getRiskEngineStats(supertest, log); + expect(stats).to.eql({}); }); }); - describe('Risk engine enabled', () => { - let hostId: string; - let userId: string; + // https://github.com/elastic/kibana/issues/183246 + it('@skipInServerlessMKI should return metrics with expected values when risk engine is enabled', async () => { + expect(await areRiskScoreIndicesEmpty({ log, es })).to.be(true); - beforeEach(async () => { - hostId = uuidv4(); - const hostEvent = buildDocument({ host: { name: 'host-1' } }, hostId); - await indexListOfDocuments( - Array(10) - .fill(hostEvent) - .map((event, index) => ({ - ...event, - 'host.name': `host-${index}`, - })) - ); + const hostId = uuidv4(); + const hostDocs = Array(10) + .fill(buildDocument({}, hostId)) + .map((event, index) => ({ + ...event, + 'host.name': `host-${index}`, + })); - userId = uuidv4(); - const userEvent = buildDocument({ user: { name: 'user-1' } }, userId); - await indexListOfDocuments( - Array(10) - .fill(userEvent) - .map((event, index) => ({ - ...event, - 'user.name': `user-${index}`, - })) - ); + const userId = uuidv4(); + const userDocs = Array(10) + .fill(buildDocument({}, userId)) + .map((event, index) => ({ + ...event, + 'user.name': `user-${index}`, + })); - await createAndSyncRuleAndAlerts({ - query: `id: ${userId} or id: ${hostId}`, - alerts: 20, - riskScore: 40, - }); + await indexListOfDocuments([...hostDocs, ...userDocs]); - await riskEngineRoutes.init(); + await createAndSyncRuleAndAlerts({ + query: `id: ${userId} or id: ${hostId}`, + alerts: 20, + riskScore: 40, }); - afterEach(async () => { - await cleanRiskEngine({ kibanaServer, es, log }); - await deleteAllAlerts(supertest, log, es); - await deleteAllRules(supertest, log); - }); + await riskEngineRoutes.init(); + + await waitForRiskScoresToBePresent({ es, log, scoreCount: 20 }); - // https://github.com/elastic/kibana/issues/183246 - it('@skipInServerlessMKI should return riskEngineMetrics with expected values', async () => { - await waitForRiskScoresToBePresent({ es, log, scoreCount: 20 }); - await retry.try(async () => { - const { - all_risk_scores_index_size: allRiskScoreIndexSize, - unique_risk_scores_index_size: uniqueRiskScoreIndexSize, - ...otherStats - } = await getRiskEngineStats(supertest, log); - const expected = { - unique_host_risk_score_total: 0, - unique_user_risk_score_total: 0, - unique_user_risk_score_day: 0, - unique_host_risk_score_day: 0, - all_user_risk_scores_total: 10, - all_host_risk_scores_total: 10, - all_user_risk_scores_total_day: 10, - all_host_risk_scores_total_day: 10, - }; - expect(otherStats).to.eql(expected); - }); + await retry.try(async () => { + const { + all_risk_scores_index_size: allRiskScoreIndexSize, + unique_risk_scores_index_size: uniqueRiskScoreIndexSize, + ...otherStats + } = await getRiskEngineStats(supertest, log); + const expected = { + unique_host_risk_score_total: 0, + unique_user_risk_score_total: 0, + unique_user_risk_score_day: 0, + unique_host_risk_score_day: 0, + all_user_risk_scores_total: 10, + all_host_risk_scores_total: 10, + all_user_risk_scores_total_day: 10, + all_host_risk_scores_total_day: 10, + }; + expect(otherStats).to.eql(expected); }); }); }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/risk_engine.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/risk_engine.ts index dbd4ed78c1896..4c39cdce1a48a 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/risk_engine.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/risk_engine.ts @@ -148,6 +148,52 @@ export const deleteRiskScoreIndices = async ({ } }; +export const areRiskScoreIndicesEmpty = async ({ + es, + namespace = 'default', + log, +}: { + es: Client; + namespace?: string; + log: ToolingLog; +}): Promise => { + const riskScoreIndex = `risk-score.risk-score-${namespace}`; + const riskScoreLatestIndex = `risk-score.risk-score-latest-${namespace}`; + let riskScoreCount = 0; + let riskScoreLatestCount = 0; + + try { + const [riskScoreCountRes, riskScoreLatestCountRes] = await Promise.all([ + es.count({ index: riskScoreIndex }), + es.count({ index: riskScoreLatestIndex }), + ]); + riskScoreCount = riskScoreCountRes.count; + riskScoreLatestCount = riskScoreLatestCountRes.count; + } catch (e) { + if (e.meta.statusCode === 404) { + return true; + } + throw e; + } + + const isEmpty = riskScoreCount === 0 && riskScoreLatestCount === 0; + + if (!isEmpty) { + log.warning( + `Risk score indices are not empty. Risk score index count: ${riskScoreCount}, Risk score latest index count: ${riskScoreLatestCount}` + ); + const [riskScoreDocs, riskScoreLatestDocs] = await Promise.all([ + es.search({ index: riskScoreIndex, size: 25 }), + es.search({ index: riskScoreLatestIndex, size: 25 }), + ]); + + log.info(`Risk score index documents: ${JSON.stringify(riskScoreDocs.hits.hits)}`); + log.info(`Risk score latest index documents: ${JSON.stringify(riskScoreLatestDocs.hits.hits)}`); + } + + return isEmpty; +}; + /** * Deletes all risk scores from a given index or indices, defaults to `risk-score.risk-score-*` * For use inside of afterEach blocks of tests diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/exceptions/rule_details_flow/add_edit_endpoint_exception.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/exceptions/rule_details_flow/add_edit_endpoint_exception.cy.ts index 61c409f63a5dc..07be6f79efd45 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/exceptions/rule_details_flow/add_edit_endpoint_exception.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/exceptions/rule_details_flow/add_edit_endpoint_exception.cy.ts @@ -134,7 +134,8 @@ describe('Add endpoint exception from rule details', { tags: ['@ess', '@serverle }); }); - describe('with exception items', () => { + // FLAKY: https://github.com/elastic/kibana/issues/179582 + describe.skip('with exception items', () => { beforeEach(() => { createEndpointExceptionList().then((response) => { createEndpointExceptionListItem({ diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/exceptions/shared_exception_lists_management/list_detail_page/list_details.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/exceptions/shared_exception_lists_management/list_detail_page/list_details.cy.ts index 5b2326ec617a6..2a98a12cba7e5 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/exceptions/shared_exception_lists_management/list_detail_page/list_details.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/exceptions/shared_exception_lists_management/list_detail_page/list_details.cy.ts @@ -41,7 +41,8 @@ const getExceptionList1 = () => ({ const EXCEPTION_LIST_NAME = 'Newly created list'; -describe('Exception list detail page', { tags: ['@ess', '@serverless'] }, () => { +// FLAKY: https://github.com/elastic/kibana/issues/180740 +describe.skip('Exception list detail page', { tags: ['@ess', '@serverless'] }, () => { beforeEach(() => { login(); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/common_flows.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/common_flows.cy.ts index abf8bc3934e21..0c4885ad35352 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/common_flows.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/common_flows.cy.ts @@ -33,8 +33,8 @@ import { fillMaxSignals, fillNote, fillReferenceUrls, - // fillRelatedIntegrations, - // fillRequiredFields, + fillRelatedIntegrations, + fillRequiredFields, fillRiskScore, fillRuleName, fillRuleTags, @@ -69,14 +69,8 @@ describe('Common rule creation flows', { tags: ['@ess', '@serverless'] }, () => it('Creates and enables a rule', function () { cy.log('Filling define section'); importSavedQuery(this.timelineId); - /* - The following steps are flaky due to a recent EUI upgrade. - - Underlying EUI issue: https://github.com/elastic/eui/issues/7761 - Issue to uncomment these once the EUI fix is in place: https://github.com/elastic/kibana/issues/183485 - */ - // fillRequiredFields(); - // fillRelatedIntegrations(); + fillRequiredFields(); + fillRelatedIntegrations(); cy.get(DEFINE_CONTINUE_BUTTON).click(); cy.log('Filling about section'); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_edit/new_terms_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_edit/new_terms_rule.cy.ts index 521c786bcbb21..63ba3e876c7d4 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_edit/new_terms_rule.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_edit/new_terms_rule.cy.ts @@ -52,7 +52,8 @@ describe( deleteAlertsAndRules(); }); - describe('with suppression configured', () => { + // FLAKY: https://github.com/elastic/kibana/issues/183941 + describe.skip('with suppression configured', () => { beforeEach(() => { createRule({ ...rule, diff --git a/x-pack/test/security_solution_endpoint/apps/integrations_feature_flag/artifact_entries_list.ts b/x-pack/test/security_solution_endpoint/apps/integrations_feature_flag/artifact_entries_list.ts index 46e333e10779d..cd5c5694c33a8 100644 --- a/x-pack/test/security_solution_endpoint/apps/integrations_feature_flag/artifact_entries_list.ts +++ b/x-pack/test/security_solution_endpoint/apps/integrations_feature_flag/artifact_entries_list.ts @@ -52,7 +52,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { .set('kbn-xsrf', 'true'); }; - describe('For each artifact list under management', function () { + // Failing: See https://github.com/elastic/kibana/issues/183860 + describe.skip('For each artifact list under management', function () { targetTags(this, ['@ess', '@serverless']); this.timeout(60_000 * 5); diff --git a/x-pack/test/tsconfig.json b/x-pack/test/tsconfig.json index 4634b40c74518..2df784cd0c8ba 100644 --- a/x-pack/test/tsconfig.json +++ b/x-pack/test/tsconfig.json @@ -175,5 +175,6 @@ "@kbn/esql-utils", "@kbn/search-types", "@kbn/analytics-ftr-helpers-plugin", + "@kbn/reporting-server", ] } diff --git a/x-pack/test_serverless/api_integration/test_suites/common/reporting/datastream.ts b/x-pack/test_serverless/api_integration/test_suites/common/reporting/datastream.ts new file mode 100644 index 0000000000000..1d336ec504250 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/common/reporting/datastream.ts @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { expect } from 'expect'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); + const reportingAPI = getService('svlReportingApi'); + const supertest = getService('supertest'); + + const archives: Record = { + ecommerce: { + data: 'x-pack/test/functional/es_archives/reporting/ecommerce', + savedObjects: 'x-pack/test/functional/fixtures/kbn_archiver/reporting/ecommerce', + }, + }; + + describe('Data Stream', () => { + before(async () => { + await esArchiver.load(archives.ecommerce.data); + await kibanaServer.importExport.load(archives.ecommerce.savedObjects); + + // for this test, we don't need to wait for the job to finish or verify the result + await reportingAPI.createReportJobInternal('csv_searchsource', { + browserTimezone: 'UTC', + objectType: 'search', + searchSource: { + index: '5193f870-d861-11e9-a311-0fa548c5f953', + query: { language: 'kuery', query: '' }, + version: true, + }, + title: 'Ecommerce Data', + version: '8.15.0', + }); + }); + + after(async () => { + await reportingAPI.deleteAllReports(); + await esArchiver.unload(archives.ecommerce.data); + await kibanaServer.importExport.unload(archives.ecommerce.savedObjects); + }); + + it('uses the datastream configuration with set ILM policy', async () => { + const { body } = await supertest + .get(`/api/index_management/data_streams/.kibana-reporting`) + .set('kbn-xsrf', 'xxx') + .set('x-elastic-internal-origin', 'xxx') + .expect(200); + + expect(body).toEqual({ + _meta: { + description: 'default kibana reporting template installed by elasticsearch', + managed: true, + }, + name: '.kibana-reporting', + indexTemplateName: '.kibana-reporting', + generation: 1, + health: 'green', + hidden: true, + indices: [ + { + name: expect.any(String), + uuid: expect.any(String), + managedBy: 'Data stream lifecycle', + preferILM: true, + }, + ], + lifecycle: { enabled: true }, + maxTimeStamp: 0, + nextGenerationManagedBy: 'Data stream lifecycle', + privileges: { delete_index: true, manage_data_stream_lifecycle: true }, + timeStampField: { name: '@timestamp' }, + storageSize: expect.any(String), + storageSizeBytes: expect.any(Number), + }); + }); + }); +} diff --git a/x-pack/test_serverless/api_integration/test_suites/common/reporting/generate_csv_discover.ts b/x-pack/test_serverless/api_integration/test_suites/common/reporting/generate_csv_discover.ts index 89e5f5a0de4a7..0450ec2a3ff30 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/reporting/generate_csv_discover.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/reporting/generate_csv_discover.ts @@ -730,7 +730,9 @@ export default function ({ getService }: FtrProviderContext) { }, }) ); - await reportingAPI.waitForJobToFinish(res.path); + await reportingAPI.waitForJobToFinish(res.path, undefined, undefined, { + timeout: 80 * 1000, + }); const csvFile = await reportingAPI.getCompletedJobOutput(res.path); expect((csvFile as string).length).to.be(4826973); expectSnapshot(createPartialCsv(csvFile)).toMatch(); diff --git a/x-pack/test_serverless/api_integration/test_suites/common/reporting/index.ts b/x-pack/test_serverless/api_integration/test_suites/common/reporting/index.ts index 3d776ec490abd..790a98257552e 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/reporting/index.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/reporting/index.ts @@ -13,5 +13,6 @@ export default ({ loadTestFile }: FtrProviderContext) => { loadTestFile(require.resolve('./management')); loadTestFile(require.resolve('./generate_csv_discover')); + loadTestFile(require.resolve('./datastream')); }); }; diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/slos/fetch_historical_summary.ts b/x-pack/test_serverless/api_integration/test_suites/observability/slos/fetch_historical_summary.ts index 32992e5a3b07b..75d8ae3af1f3c 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/slos/fetch_historical_summary.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/slos/fetch_historical_summary.ts @@ -82,7 +82,8 @@ export default function ({ getService }: FtrProviderContext) { }); expect(response[0].sloId).to.eql(SLO_ID); expect(response[0].instanceId).to.eql(ALL_VALUE); - expect(response[0].data).to.have.length(168); // 7 days * 24 hours/day * 1 bucket/hour + const numberOfBuckets = response[0].data.length; + expect(numberOfBuckets).to.be.within(168, 170); // 7 days * 24 hours/day * 1 bucket/hour + 2 extra bucket due to histogram agg rounding const last = response[0].data.pop(); expect(last?.errorBudget).to.eql({ consumed: 1, @@ -117,7 +118,8 @@ export default function ({ getService }: FtrProviderContext) { }); expect(response[0].sloId).to.eql(SLO_ID); expect(response[0].instanceId).to.eql(ALL_VALUE); - expect(response[0].data).to.have.length(168); // 7 days * 24 hours/day * 1 bucket/hour + const numberOfBuckets = response[0].data.length; + expect(numberOfBuckets).to.be.within(168, 170); // 7 days * 24 hours/day * 1 bucket/hour + 2 extra bucket due to histogram agg rounding const last = response[0].data.pop(); expect(last?.errorBudget).to.eql({ consumed: 0, diff --git a/x-pack/test_serverless/functional/page_objects/index.ts b/x-pack/test_serverless/functional/page_objects/index.ts index ebc85de7d332c..f1604d48508e2 100644 --- a/x-pack/test_serverless/functional/page_objects/index.ts +++ b/x-pack/test_serverless/functional/page_objects/index.ts @@ -21,7 +21,6 @@ import { SvlRuleDetailsPageProvider } from './svl_rule_details_ui_page'; import { SvlSearchConnectorsPageProvider } from './svl_search_connectors_page'; import { SvlManagementPageProvider } from './svl_management_page'; import { SvlIngestPipelines } from './svl_ingest_pipelines'; -import { SvlPlaygroundPageProvider } from './svl_playground_page'; export const pageObjects = { ...xpackFunctionalPageObjects, @@ -39,5 +38,4 @@ export const pageObjects = { svlRuleDetailsUI: SvlRuleDetailsPageProvider, svlManagementPage: SvlManagementPageProvider, svlIngestPipelines: SvlIngestPipelines, - svlPlaygroundUI: SvlPlaygroundPageProvider, }; diff --git a/x-pack/test_serverless/functional/page_objects/svl_playground_page.ts b/x-pack/test_serverless/functional/page_objects/svl_playground_page.ts deleted file mode 100644 index e0c26c031eb50..0000000000000 --- a/x-pack/test_serverless/functional/page_objects/svl_playground_page.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FtrProviderContext } from '../ftr_provider_context'; - -export function SvlPlaygroundPageProvider({ getService }: FtrProviderContext) { - const testSubjects = getService('testSubjects'); - return { - PlaygrounStartChatPage: { - async expectPlaygroundStartChatPageComponentsToExist() { - await testSubjects.existOrFail('chat-playground-home-page-title'); - await testSubjects.existOrFail('selectIndicesChatPanel'); - await testSubjects.existOrFail('startChatButton'); - }, - - async expectPlaygroundHeaderComponentsToExist() { - await testSubjects.existOrFail('playground-header-actions'); - await testSubjects.existOrFail('playground-documentation-link'); - }, - }, - }; -} 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 7445596a7175f..29bbc4b3c3e9c 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 @@ -261,16 +261,28 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { beforeEach(async () => { await PageObjects.common.navigateToApp('discover'); await PageObjects.timePicker.setDefaultAbsoluteRange(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); }); it('shows Discover and Lens requests in Inspector', async () => { await PageObjects.discover.selectTextBaseLang(); await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.discover.waitUntilSearchingHasFinished(); - await inspector.open(); - const requestNames = await inspector.getRequestNames(); - expect(requestNames).to.contain('Table'); - expect(requestNames).to.contain('Visualization'); + let retries = 0; + await retry.try(async () => { + if (retries > 0) { + await inspector.close(); + await testSubjects.click('querySubmitButton'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + } + await inspector.open(); + retries = retries + 1; + const requestNames = await inspector.getRequestNames(); + expect(requestNames).to.contain('Table'); + expect(requestNames).to.contain('Visualization'); + }); }); }); diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/x_pack/reporting.ts b/x-pack/test_serverless/functional/test_suites/common/discover/x_pack/reporting.ts index 3a4cee55dad94..b5eb49519ce31 100644 --- a/x-pack/test_serverless/functional/test_suites/common/discover/x_pack/reporting.ts +++ b/x-pack/test_serverless/functional/test_suites/common/discover/x_pack/reporting.ts @@ -35,14 +35,14 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await browser.refresh(); }; - const getReport = async () => { + const getReport = async ({ timeout } = { timeout: 60 * 1000 }) => { // close any open notification toasts await toasts.dismissAll(); await PageObjects.reporting.openExportTab(); await PageObjects.reporting.clickGenerateReportButton(); - const url = await PageObjects.reporting.getReportURL(60000); + const url = await PageObjects.reporting.getReportURL(timeout); // TODO: Fetch CSV client side in Serverless since `PageObjects.reporting.getResponse()` // doesn't work because it relies on `SecurityService.testUserSupertest` const res: { status: number; contentType: string | null; text: string } = @@ -184,7 +184,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.discover.saveSearch('large export'); // match file length, the beginning and the end of the csv file contents - const { text: csvFile } = await getReport(); + const { text: csvFile } = await getReport({ timeout: 80 * 1000 }); expect(csvFile.length).to.be(4826973); expectSnapshot(csvFile.slice(0, 5000)).toMatch(); expectSnapshot(csvFile.slice(-5000)).toMatch(); diff --git a/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_flyout.ts b/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_flyout.ts index 9688c177c2e73..2f2c40932ceaf 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_flyout.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_flyout.ts @@ -31,7 +31,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const to = '2024-01-01T12:00:00.000Z'; const excludeKeysFromServerless = ['size']; // https://github.com/elastic/kibana/issues/178954 - describe('Dataset quality flyout', function () { + // FLAKY: https://github.com/elastic/kibana/issues/183771 + describe.skip('Dataset quality flyout', function () { this.tags(['failsOnMKI']); // Failing https://github.com/elastic/kibana/issues/183495 before(async () => { diff --git a/x-pack/test_serverless/functional/test_suites/search/playground_overview.ts b/x-pack/test_serverless/functional/test_suites/search/playground_overview.ts index f726287de0fb7..40a36362a585e 100644 --- a/x-pack/test_serverless/functional/test_suites/search/playground_overview.ts +++ b/x-pack/test_serverless/functional/test_suites/search/playground_overview.ts @@ -5,24 +5,147 @@ * 2.0. */ -import { FtrProviderContext } from '../../ftr_provider_context'; +import type SuperTest from 'supertest'; import { testHasEmbeddedConsole } from './embedded_console'; +import { FtrProviderContext } from '../../ftr_provider_context'; +import { RoleCredentials } from '../../../shared/services'; + +const indexName = 'basic_index'; +const esArchiveIndex = 'test/api_integration/fixtures/es_archiver/index_patterns/basic_index'; +async function createOpenAIConnector({ + supertest, + requestHeader = {}, + apiKeyHeader = {}, +}: { + supertest: SuperTest.Agent; + requestHeader?: Record; + apiKeyHeader?: Record; +}): Promise<() => Promise> { + const config = { + apiProvider: 'OpenAI', + defaultModel: 'gpt-4', + apiUrl: 'http://localhost:3002', + }; + + const connector: { id: string } | undefined = ( + await supertest + .post('/api/actions/connector') + .set(requestHeader) + .set(apiKeyHeader) + .send({ + name: 'test Open AI', + connector_type_id: '.gen-ai', + config, + secrets: { + apiKey: 'genAiApiKey', + }, + }) + .expect(200) + ).body; + + return async () => { + if (connector) { + await supertest + .delete(`/api/actions/connector/${connector.id}`) + .set(requestHeader) + .set(apiKeyHeader) + .expect(204); + } + }; +} + +export default function ({ getPageObjects, getService }: FtrProviderContext) { + const pageObjects = getPageObjects(['svlCommonPage', 'svlCommonNavigation', 'searchPlayground']); + const svlCommonApi = getService('svlCommonApi'); + const svlUserManager = getService('svlUserManager'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const esArchiver = getService('esArchiver'); + const createIndex = async () => await esArchiver.load(esArchiveIndex); + let roleAuthc: RoleCredentials; + + describe('Serverless Playground Overview', function () { + // see details: https://github.com/elastic/kibana/issues/183893 + this.tags(['failsOnMKI']); + + let removeOpenAIConnector: () => Promise; + let createConnector: () => Promise; -export default function ({ getPageObjects }: FtrProviderContext) { - const pageObjects = getPageObjects(['svlCommonPage', 'svlCommonNavigation', 'svlPlaygroundUI']); - describe('Playground', function () { before(async () => { await pageObjects.svlCommonPage.login(); - await pageObjects.svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'searchPlayground' }); + await pageObjects.svlCommonNavigation.sidenav.clickLink({ + deepLinkId: 'searchPlayground', + }); + + const requestHeader = svlCommonApi.getInternalRequestHeader(); + roleAuthc = await svlUserManager.createApiKeyForRole('admin'); + createConnector = async () => { + removeOpenAIConnector = await createOpenAIConnector({ + supertest: supertestWithoutAuth, + requestHeader, + apiKeyHeader: roleAuthc.apiKeyHeader, + }); + }; }); after(async () => { + await removeOpenAIConnector?.(); + await esArchiver.unload(esArchiveIndex); + await svlUserManager.invalidateApiKeyForRole(roleAuthc); await pageObjects.svlCommonPage.forceLogout(); }); - it('playground app is loaded', async () => { - await pageObjects.svlPlaygroundUI.PlaygrounStartChatPage.expectPlaygroundStartChatPageComponentsToExist(); - await pageObjects.svlPlaygroundUI.PlaygrounStartChatPage.expectPlaygroundHeaderComponentsToExist(); + describe('start chat page', () => { + it('playground app is loaded', async () => { + await pageObjects.searchPlayground.PlaygroundStartChatPage.expectPlaygroundStartChatPageComponentsToExist(); + await pageObjects.searchPlayground.PlaygroundStartChatPage.expectPlaygroundHeaderComponentsToExist(); + }); + + it('show no index callout', async () => { + await pageObjects.searchPlayground.PlaygroundStartChatPage.expectNoIndexCalloutExists(); + await pageObjects.searchPlayground.PlaygroundStartChatPage.expectCreateIndexButtonToMissed(); + }); + + it('hide no index callout when index added', async () => { + await createIndex(); + await pageObjects.searchPlayground.PlaygroundStartChatPage.expectSelectIndex(indexName); + }); + + it('show add connector button', async () => { + await pageObjects.searchPlayground.PlaygroundStartChatPage.expectAddConnectorButtonExists(); + }); + + it('click add connector button opens connector flyout', async () => { + await pageObjects.searchPlayground.PlaygroundStartChatPage.expectOpenConnectorPagePlayground(); + }); + + it('hide gen ai panel when connector exists', async () => { + await pageObjects.searchPlayground.PlaygroundStartChatPage.expectHideGenAIPanelConnector( + createConnector + ); + }); + + it('show chat page', async () => { + await pageObjects.searchPlayground.PlaygroundStartChatPage.expectSelectIndex(indexName); + await pageObjects.searchPlayground.PlaygroundStartChatPage.expectToStartChatPage(); + }); + }); + + describe('chat page', () => { + it('chat works', async () => { + await pageObjects.searchPlayground.PlaygroundChatPage.expectChatWorks(); + }); + + it('open view code', async () => { + await pageObjects.searchPlayground.PlaygroundChatPage.expectOpenViewCode(); + }); + + it('show fields and code in view query', async () => { + await pageObjects.searchPlayground.PlaygroundChatPage.expectViewQueryHasFields(); + }); + + it('show edit context', async () => { + await pageObjects.searchPlayground.PlaygroundChatPage.expectEditContextOpens(); + }); }); it('has embedded console', async () => { diff --git a/x-pack/test_serverless/functional/test_suites/security/ml/trained_models_list.ts b/x-pack/test_serverless/functional/test_suites/security/ml/trained_models_list.ts index 8e6928b9817a2..745f2b8d4a65f 100644 --- a/x-pack/test_serverless/functional/test_suites/security/ml/trained_models_list.ts +++ b/x-pack/test_serverless/functional/test_suites/security/ml/trained_models_list.ts @@ -11,10 +11,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const svlMl = getService('svlMl'); const PageObjects = getPageObjects(['svlCommonPage']); - // failsOnMKI, see https://github.com/elastic/kibana/issues/180481 describe('Trained models list', function () { - this.tags(['failsOnMKI']); - before(async () => { await PageObjects.svlCommonPage.login(); await ml.api.syncSavedObjects(); diff --git a/x-pack/test_serverless/shared/lib/security/kibana_roles/project_controller_security_roles.yml b/x-pack/test_serverless/shared/lib/security/kibana_roles/project_controller_security_roles.yml index b1e54563ef488..9f3220959c486 100644 --- a/x-pack/test_serverless/shared/lib/security/kibana_roles/project_controller_security_roles.yml +++ b/x-pack/test_serverless/shared/lib/security/kibana_roles/project_controller_security_roles.yml @@ -474,6 +474,7 @@ soc_manager: - feature_siem.actions_log_management_all - feature_siem.file_operations_all - feature_siem.execute_operations_all + - feature_siem.scan_operations_all - feature_securitySolutionCases.all - feature_securitySolutionAssistant.all - feature_actions.all @@ -656,6 +657,7 @@ endpoint_operations_analyst: - feature_siem.actions_log_management_all # Response History - feature_siem.file_operations_all - feature_siem.execute_operations_all # Execute + - feature_siem.scan_operations_all - feature_securitySolutionCases.all - feature_securitySolutionAssistant.all - feature_actions.all @@ -734,4 +736,4 @@ endpoint_policy_manager: - feature_graph.all - feature_maps.all - feature_visualize.all - resources: "*" \ No newline at end of file + resources: "*" diff --git a/yarn.lock b/yarn.lock index 63f50a8f16e93..5f1865d8d5f8a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1735,10 +1735,10 @@ resolved "https://registry.yarnpkg.com/@elastic/eslint-plugin-eui/-/eslint-plugin-eui-0.0.2.tgz#56b9ef03984a05cc213772ae3713ea8ef47b0314" integrity sha512-IoxURM5zraoQ7C8f+mJb9HYSENiZGgRVcG4tLQxE61yHNNRDXtGDWTZh8N1KIHcsqN1CEPETjuzBXkJYF/fDiQ== -"@elastic/eui@94.3.0": - version "94.3.0" - resolved "https://registry.yarnpkg.com/@elastic/eui/-/eui-94.3.0.tgz#77c07701128b6443e2ea55e2462ef0ccadd64582" - integrity sha512-qJTLrQYe11MPTX+8AqifJVYLDyO8VqdFWqPVJRYel11l/FvJOqyQi50x+xQK8I7h73TF50xywtUHCfhfkqpbYg== +"@elastic/eui@94.5.1": + version "94.5.1" + resolved "https://registry.yarnpkg.com/@elastic/eui/-/eui-94.5.1.tgz#cdaab02483a419bfc910be9d75a310b60141a611" + integrity sha512-VopgWoljYAkhrK602vP9QJSbGcGVTT57YkWjAGHVV57YRdKJWXvHt3sbBUdangquxYj4ZC2GXM81p7mMxiCOXA== dependencies: "@hello-pangea/dnd" "^16.6.0" "@types/lodash" "^4.14.202" @@ -5091,6 +5091,10 @@ version "0.0.0" uid "" +"@kbn/langchain@link:x-pack/packages/kbn-langchain": + version "0.0.0" + uid "" + "@kbn/language-documentation-popover@link:packages/kbn-language-documentation-popover": version "0.0.0" uid "" @@ -6291,10 +6295,6 @@ version "0.0.0" uid "" -"@kbn/solution-nav-es@link:packages/solution-nav/es": - version "0.0.0" - uid "" - "@kbn/solution-nav-oblt@link:packages/solution-nav/oblt": version "0.0.0" uid "" @@ -11437,6 +11437,11 @@ acorn-import-assertions@^1.9.0: resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac" integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA== +acorn-import-attributes@^1.9.5: + version "1.9.5" + resolved "https://registry.yarnpkg.com/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz#7eb1557b1ba05ef18b5ed0ec67591bfab04688ef" + integrity sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ== + acorn-jsx@^5.3.1, acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" @@ -15940,10 +15945,10 @@ elastic-apm-node@3.46.0: traverse "^0.6.6" unicode-byte-truncate "^1.0.0" -elastic-apm-node@^4.5.3: - version "4.5.3" - resolved "https://registry.yarnpkg.com/elastic-apm-node/-/elastic-apm-node-4.5.3.tgz#8015f1525f6cd45daef6a48a88d93dbaf5899212" - integrity sha512-FE+srHVTtvDp/SfY76yxSIupCU8Z30WuOx1Yf3plUXeyLuKqq9YRk6uX0Jleb1jfwG58lvabpeU0u9YmS1YdrA== +elastic-apm-node@^4.5.4: + version "4.5.4" + resolved "https://registry.yarnpkg.com/elastic-apm-node/-/elastic-apm-node-4.5.4.tgz#add7c5a53f8a4ec29989e3365c9f2053ec64a20d" + integrity sha512-PqX8a5PdWo+mtH1Vn+xjmhJpa2RE9zbKDKFkKoENKG118KVgukxhFlVIpb3qrht9aeRkPxHqQsPNtNV3ljPjew== dependencies: "@elastic/ecs-pino-format" "^1.5.0" "@opentelemetry/api" "^1.4.1" @@ -15963,7 +15968,7 @@ elastic-apm-node@^4.5.3: fast-safe-stringify "^2.0.7" fast-stream-to-buffer "^1.0.0" http-headers "^3.0.2" - import-in-the-middle "1.7.3" + import-in-the-middle "1.7.4" json-bigint "^1.0.0" lru-cache "^10.0.1" measured-reporting "^1.51.1" @@ -19269,13 +19274,13 @@ import-fresh@^3.1.0, import-fresh@^3.2.1, import-fresh@^3.3.0: parent-module "^1.0.0" resolve-from "^4.0.0" -import-in-the-middle@1.7.3: - version "1.7.3" - resolved "https://registry.yarnpkg.com/import-in-the-middle/-/import-in-the-middle-1.7.3.tgz#ffa784cdd57a47d2b68d2e7dd33070ff06baee43" - integrity sha512-R2I11NRi0lI3jD2+qjqyVlVEahsejw7LDnYEbGb47QEFjczE3bZYsmWheCTQA+LFs2DzOQxR7Pms7naHW1V4bQ== +import-in-the-middle@1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/import-in-the-middle/-/import-in-the-middle-1.7.4.tgz#508da6e91cfa84f210dcdb6c0a91ab0c9e8b3ebc" + integrity sha512-Lk+qzWmiQuRPPulGQeK5qq0v32k2bHnWrRPFgqyvhw7Kkov5L6MOLOIU3pcWeujc9W4q54Cp3Q2WV16eQkc7Bg== dependencies: acorn "^8.8.2" - acorn-import-assertions "^1.9.0" + acorn-import-attributes "^1.9.5" cjs-module-lexer "^1.2.2" module-details-from-path "^1.0.3"